├── .cargo └── config.toml ├── .config └── nextest.toml ├── .dockerignore ├── .github └── workflows │ ├── dependencies.yml │ ├── docker.yml │ ├── integration.yml │ ├── lint-actions.yml │ ├── lint.yml │ └── unit.yml ├── .gitignore ├── CODEOWNERS ├── Cargo.lock ├── Cargo.toml ├── Cross.toml ├── Dockerfile ├── Dockerfile.cross ├── LICENSE-APACHE ├── LICENSE-MIT ├── Makefile ├── README.md ├── SECURITY.md ├── bin └── alphanet │ ├── Cargo.toml │ └── src │ └── main.rs ├── clippy.toml ├── crates ├── node │ ├── Cargo.toml │ └── src │ │ ├── chainspec.rs │ │ ├── evm.rs │ │ ├── lib.rs │ │ └── node.rs ├── precompile │ ├── Cargo.toml │ └── src │ │ ├── addresses.rs │ │ ├── lib.rs │ │ └── secp256r1.rs ├── testing │ ├── Cargo.toml │ ├── resources │ │ └── eip3074 │ │ │ ├── foundry.toml │ │ │ ├── out │ │ │ ├── BaseAuth.sol │ │ │ │ └── BaseAuth.json │ │ │ ├── GasSponsorInvoker.sol │ │ │ │ └── GasSponsorInvoker.json │ │ │ └── SenderRecorder.sol │ │ │ │ └── SenderRecorder.json │ │ │ └── src │ │ │ ├── BaseAuth.sol │ │ │ ├── GasSponsorInvoker.sol │ │ │ └── SenderRecorder.sol │ └── src │ │ ├── lib.rs │ │ └── tests.rs └── wallet │ ├── Cargo.toml │ └── src │ └── lib.rs ├── deny.toml ├── etc ├── alphanet-genesis.json ├── alphanet-rollup.json ├── deploy-config │ └── sepolia.json ├── dev-genesis.json └── kurtosis.yaml └── rustfmt.toml /.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [alias] 2 | docs = "doc --workspace --all-features --no-deps" 3 | -------------------------------------------------------------------------------- /.config/nextest.toml: -------------------------------------------------------------------------------- 1 | [test-groups] 2 | serial-integration = { max-threads = 1 } 3 | 4 | [[profile.default.overrides]] 5 | filter = 'package(alphanet-testing)' 6 | test-group = 'serial-integration' -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | # exclude everything 2 | * 3 | 4 | # include source files 5 | !/bin 6 | !/crates 7 | !Cargo.lock 8 | !Cargo.toml 9 | !Cross.toml 10 | !deny.toml 11 | !Makefile 12 | 13 | # include for vergen constants 14 | !/.git 15 | 16 | # include licenses 17 | !LICENSE-* 18 | 19 | # include dist directory, where the reth binary is located after compilation 20 | !/dist 21 | 22 | # include L2 genesis files 23 | !/etc/alphanet-genesis.json 24 | !/etc/dev-genesis.json 25 | 26 | # include example files 27 | !/examples 28 | -------------------------------------------------------------------------------- /.github/workflows/dependencies.yml: -------------------------------------------------------------------------------- 1 | # Runs `cargo update` periodically. 2 | 3 | name: Update Dependencies 4 | 5 | on: 6 | schedule: 7 | # Run weekly 8 | - cron: "0 0 * * SUN" 9 | workflow_dispatch: 10 | # Needed so we can run it manually 11 | 12 | env: 13 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 14 | BRANCH: cargo-update 15 | TITLE: "chore(deps): weekly `cargo update`" 16 | BODY: | 17 | Automation to keep dependencies in `Cargo.lock` current. 18 | 19 |
cargo update log 20 |

21 | 22 | ```log 23 | $cargo_update_log 24 | ``` 25 | 26 |

27 |
28 | 29 | jobs: 30 | update: 31 | name: Update 32 | runs-on: ubuntu-latest 33 | steps: 34 | - uses: actions/checkout@v4 35 | - uses: dtolnay/rust-toolchain@nightly 36 | 37 | - name: cargo update 38 | # Remove first line that always just says "Updating crates.io index" 39 | run: cargo update --color never 2>&1 | sed '/crates.io index/d' | tee -a cargo_update.log 40 | 41 | - name: craft commit message and PR body 42 | id: msg 43 | run: | 44 | export cargo_update_log="$(cat cargo_update.log)" 45 | 46 | echo "commit_message<> $GITHUB_OUTPUT 47 | printf "%s\n\n%s\n" $TITLE $cargo_update_log >> $GITHUB_OUTPUT 48 | echo "EOF" >> $GITHUB_OUTPUT 49 | 50 | echo "body<> $GITHUB_OUTPUT 51 | echo "$BODY" | envsubst >> $GITHUB_OUTPUT 52 | echo "EOF" >> $GITHUB_OUTPUT 53 | 54 | - name: Create Pull Request 55 | uses: peter-evans/create-pull-request@v5 56 | with: 57 | add-paths: ./Cargo.lock 58 | commit-message: ${{ steps.msg.outputs.commit_message }} 59 | title: ${{ env.TITLE }} 60 | body: ${{ steps.msg.outputs.body }} 61 | branch: ${{ env.BRANCH }} 62 | -------------------------------------------------------------------------------- /.github/workflows/docker.yml: -------------------------------------------------------------------------------- 1 | # Publishes the Docker image. 2 | 3 | name: docker 4 | 5 | on: 6 | workflow_dispatch: {} 7 | push: 8 | tags: 9 | - v* 10 | 11 | env: 12 | REPO_NAME: ${{ github.repository_owner }}/alphanet 13 | IMAGE_NAME: ${{ github.repository_owner }}/alphanet 14 | CARGO_TERM_COLOR: always 15 | DOCKER_IMAGE_NAME: ghcr.io/${{ github.repository_owner }}/alphanet 16 | DOCKER_USERNAME: ${{ github.actor }} 17 | 18 | jobs: 19 | build: 20 | name: build and push 21 | runs-on: ubuntu-20.04 22 | permissions: 23 | packages: write 24 | contents: read 25 | steps: 26 | - uses: actions/checkout@v4 27 | - uses: dtolnay/rust-toolchain@stable 28 | - uses: Swatinem/rust-cache@v2 29 | with: 30 | cache-on-failure: true 31 | - uses: taiki-e/install-action@cross 32 | - name: Log in to Docker 33 | run: | 34 | echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io --username ${DOCKER_USERNAME} --password-stdin 35 | - name: Set up Docker builder 36 | run: | 37 | docker run --privileged --rm tonistiigi/binfmt --install arm64,amd64 38 | docker buildx create --use --name cross-builder 39 | - name: Build and push image, tag as "latest" 40 | if: ${{ ! contains(github.event.ref, '-alpha') }} 41 | run: make docker-build-push-latest 42 | - name: Build and push image 43 | if: ${{ contains(github.event.ref, '-alpha') }} 44 | run: make docker-build-push 45 | -------------------------------------------------------------------------------- /.github/workflows/integration.yml: -------------------------------------------------------------------------------- 1 | # Runs integration tests. 2 | 3 | name: integration 4 | 5 | on: 6 | pull_request: 7 | merge_group: 8 | push: 9 | branches: [main] 10 | 11 | env: 12 | CARGO_TERM_COLOR: always 13 | 14 | concurrency: 15 | group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} 16 | cancel-in-progress: true 17 | 18 | jobs: 19 | test: 20 | name: test 21 | env: 22 | RUST_BACKTRACE: 1 23 | timeout-minutes: 60 24 | runs-on: ubuntu-latest 25 | steps: 26 | - uses: actions/checkout@v4 27 | - uses: dtolnay/rust-toolchain@stable 28 | - uses: taiki-e/install-action@nextest 29 | - uses: Swatinem/rust-cache@v2 30 | with: 31 | cache-on-failure: true 32 | - name: Check bytecode is up to date with source 33 | run: | 34 | make check-bytecode 35 | - name: Run tests 36 | run: | 37 | cargo nextest run \ 38 | --locked \ 39 | --workspace \ 40 | -E 'kind(test)' 41 | 42 | integration-success: 43 | name: integration success 44 | runs-on: ubuntu-latest 45 | if: always() 46 | needs: [test] 47 | timeout-minutes: 30 48 | steps: 49 | - name: Decide whether the needed jobs succeeded or failed 50 | uses: re-actors/alls-green@release/v1 51 | with: 52 | jobs: ${{ toJSON(needs) }} 53 | -------------------------------------------------------------------------------- /.github/workflows/lint-actions.yml: -------------------------------------------------------------------------------- 1 | name: Lint GitHub Actions workflows 2 | on: 3 | pull_request: 4 | merge_group: 5 | push: 6 | branches: [main] 7 | 8 | jobs: 9 | actionlint: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v4 13 | - name: Download actionlint 14 | id: get_actionlint 15 | run: bash <(curl https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash) 16 | shell: bash 17 | - name: Check workflow files 18 | run: SHELLCHECK_OPTS="-S error" ${{ steps.get_actionlint.outputs.executable }} -color 19 | shell: bash 20 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: lint 2 | 3 | on: 4 | pull_request: 5 | merge_group: 6 | push: 7 | branches: [main] 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | 12 | jobs: 13 | clippy-binaries: 14 | name: clippy 15 | runs-on: ubuntu-latest 16 | timeout-minutes: 30 17 | steps: 18 | - uses: actions/checkout@v4 19 | - uses: dtolnay/rust-toolchain@clippy 20 | - uses: Swatinem/rust-cache@v2 21 | with: 22 | cache-on-failure: true 23 | - run: cargo clippy --bin alphanet --workspace --features "asm-keccak jemalloc jemalloc-prof min-error-logs min-warn-logs min-info-logs min-debug-logs min-trace-logs" 24 | env: 25 | RUSTFLAGS: -D warnings 26 | 27 | clippy: 28 | name: clippy 29 | runs-on: ubuntu-latest 30 | timeout-minutes: 30 31 | steps: 32 | - uses: actions/checkout@v4 33 | - uses: dtolnay/rust-toolchain@clippy 34 | - uses: Swatinem/rust-cache@v2 35 | with: 36 | cache-on-failure: true 37 | - run: cargo clippy --workspace --examples --tests --benches --all-features 38 | env: 39 | RUSTFLAGS: -D warnings 40 | 41 | crate-checks: 42 | runs-on: ubuntu-latest 43 | timeout-minutes: 30 44 | steps: 45 | - uses: actions/checkout@v4 46 | - uses: dtolnay/rust-toolchain@stable 47 | - uses: taiki-e/install-action@cargo-hack 48 | - uses: Swatinem/rust-cache@v2 49 | with: 50 | cache-on-failure: true 51 | - run: cargo hack check 52 | 53 | msrv: 54 | name: MSRV 55 | runs-on: ubuntu-latest 56 | timeout-minutes: 30 57 | steps: 58 | - uses: actions/checkout@v4 59 | - uses: dtolnay/rust-toolchain@master 60 | with: 61 | toolchain: "1.81" # MSRV 62 | - uses: Swatinem/rust-cache@v2 63 | with: 64 | cache-on-failure: true 65 | - run: cargo build --bin alphanet --workspace 66 | env: 67 | RUSTFLAGS: -D warnings 68 | 69 | docs: 70 | name: docs 71 | runs-on: ubuntu-latest 72 | timeout-minutes: 30 73 | steps: 74 | - uses: actions/checkout@v4 75 | - uses: dtolnay/rust-toolchain@nightly 76 | - uses: Swatinem/rust-cache@v2 77 | with: 78 | cache-on-failure: true 79 | - run: cargo docs --document-private-items 80 | env: 81 | # Keep in sync with ./book.yml:jobs.build 82 | # This should only add `-D warnings` 83 | RUSTDOCFLAGS: 84 | --cfg docsrs --show-type-layout --generate-link-to-definition --enable-index-page 85 | -Zunstable-options -D warnings 86 | 87 | fmt: 88 | name: fmt 89 | runs-on: ubuntu-latest 90 | timeout-minutes: 30 91 | steps: 92 | - uses: actions/checkout@v4 93 | - uses: dtolnay/rust-toolchain@nightly 94 | with: 95 | components: rustfmt 96 | - run: cargo fmt --all --check 97 | 98 | lint-success: 99 | name: lint success 100 | runs-on: ubuntu-latest 101 | if: always() 102 | needs: [clippy-binaries, clippy, crate-checks, docs, fmt] 103 | timeout-minutes: 30 104 | steps: 105 | - name: Decide whether the needed jobs succeeded or failed 106 | uses: re-actors/alls-green@release/v1 107 | with: 108 | jobs: ${{ toJSON(needs) }} 109 | -------------------------------------------------------------------------------- /.github/workflows/unit.yml: -------------------------------------------------------------------------------- 1 | # Runs unit tests. 2 | 3 | name: unit 4 | 5 | on: 6 | pull_request: 7 | merge_group: 8 | push: 9 | branches: [main] 10 | 11 | env: 12 | CARGO_TERM_COLOR: always 13 | 14 | concurrency: 15 | group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} 16 | cancel-in-progress: true 17 | 18 | jobs: 19 | test: 20 | name: test 21 | env: 22 | RUST_BACKTRACE: 1 23 | timeout-minutes: 30 24 | runs-on: ubuntu-latest 25 | steps: 26 | - uses: actions/checkout@v4 27 | - uses: dtolnay/rust-toolchain@stable 28 | - uses: Swatinem/rust-cache@v2 29 | with: 30 | cache-on-failure: true 31 | - uses: taiki-e/install-action@nextest 32 | - name: Run tests 33 | run: | 34 | cargo nextest run \ 35 | --locked \ 36 | --workspace \ 37 | -E "kind(lib) | kind(bin) | kind(proc-macro)" 38 | 39 | doc: 40 | name: doc tests 41 | env: 42 | RUST_BACKTRACE: 1 43 | timeout-minutes: 30 44 | runs-on: ubuntu-latest 45 | steps: 46 | - uses: actions/checkout@v4 47 | - uses: dtolnay/rust-toolchain@stable 48 | - uses: Swatinem/rust-cache@v2 49 | with: 50 | cache-on-failure: true 51 | - name: Run doctests 52 | run: cargo test --doc --workspace 53 | 54 | unit-success: 55 | name: unit success 56 | runs-on: ubuntu-latest 57 | if: always() 58 | needs: [test] 59 | timeout-minutes: 30 60 | steps: 61 | - name: Decide whether the needed jobs succeeded or failed 62 | uses: re-actors/alls-green@release/v1 63 | with: 64 | jobs: ${{ toJSON(needs) }} 65 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | debug/ 4 | target/ 5 | 6 | # These are backup files generated by rustfmt 7 | **/*.rs.bk 8 | 9 | # MSVC Windows builds of rustc generate these, which store debugging information 10 | *.pdb 11 | 12 | # Generated by Intellij-based IDEs. 13 | .idea 14 | 15 | # Generated by MacOS 16 | .DS_Store 17 | 18 | # Proptest data 19 | proptest-regressions/ 20 | 21 | # Release artifacts 22 | dist/ 23 | 24 | # VSCode 25 | .vscode 26 | 27 | # Coverage report 28 | lcov.info 29 | 30 | # Rust bug report 31 | rustc-ice-* 32 | 33 | crates/testing/resources/**/cache/* 34 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @fgimenez @Rjected @onbjerg 2 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "bin/alphanet/", 4 | "crates/node", 5 | "crates/precompile", 6 | "crates/testing", 7 | "crates/wallet", 8 | ] 9 | default-members = ["bin/alphanet/"] 10 | resolver = "2" 11 | 12 | [workspace.package] 13 | version = "0.0.0" 14 | edition = "2021" 15 | rust-version = "1.81" 16 | authors = [] 17 | license = "MIT OR Apache-2.0" 18 | repository = "https://github.com/paradigmxyz/alphanet" 19 | keywords = ["ethereum", "crypto"] 20 | categories = ["cryptography", "cryptography::cryptocurrencies"] 21 | 22 | [workspace.metadata.docs.rs] 23 | all-features = true 24 | rustdoc-args = ["--cfg", "docsrs"] 25 | 26 | [workspace.lints.clippy] 27 | dbg-macro = "warn" 28 | manual-string-new = "warn" 29 | uninlined-format-args = "warn" 30 | use-self = "warn" 31 | 32 | [workspace.lints.rust] 33 | rust-2018-idioms = "deny" 34 | unreachable-pub = "warn" 35 | unused-must-use = "deny" 36 | missing_docs = "warn" 37 | 38 | [workspace.lints.rustdoc] 39 | all = "warn" 40 | 41 | [profile.release] 42 | opt-level = 3 43 | lto = "thin" 44 | debug = "line-tables-only" 45 | strip = true 46 | panic = "unwind" 47 | codegen-units = 16 48 | 49 | # Use the `--profile profiling` flag to show symbols in release mode. 50 | # e.g. `cargo build --profile profiling` 51 | [profile.profiling] 52 | inherits = "release" 53 | debug = 2 54 | strip = false 55 | 56 | [workspace.dependencies] 57 | # alphanet 58 | alphanet-node = { path = "crates/node" } 59 | alphanet-precompile = { path = "crates/precompile" } 60 | alphanet-wallet = { path = "crates/wallet" } 61 | 62 | alloy = { version = "0.4", features = [ 63 | "contract", 64 | "providers", 65 | "provider-http", 66 | "signers", 67 | ] } 68 | alloy-network = { version = "0.4" } 69 | alloy-primitives = { version = "0.8.7" } 70 | alloy-rpc-types = { version = "0.4" } 71 | alloy-signer-local = { version = "0.4", features = ["mnemonic"] } 72 | 73 | # tokio 74 | tokio = { version = "1.21", default-features = false } 75 | 76 | # reth 77 | reth = { git = "https://github.com/paradigmxyz/reth.git", rev = "6d3aa5a" } 78 | reth-chainspec = { git = "https://github.com/paradigmxyz/reth.git", rev = "6d3aa5a", features = [ 79 | "optimism", 80 | ] } 81 | reth-cli = { git = "https://github.com/paradigmxyz/reth.git", rev = "6d3aa5a" } 82 | reth-cli-util = { git = "https://github.com/paradigmxyz/reth.git", rev = "6d3aa5a" } 83 | reth-rpc-eth-api = { git = "https://github.com/paradigmxyz/reth.git", rev = "6d3aa5a" } 84 | reth-node-api = { git = "https://github.com/paradigmxyz/reth.git", rev = "6d3aa5a" } 85 | reth-node-builder = { git = "https://github.com/paradigmxyz/reth.git", rev = "6d3aa5a" } 86 | reth-node-core = { git = "https://github.com/paradigmxyz/reth.git", rev = "6d3aa5a", features = [ 87 | "optimism", 88 | ] } 89 | reth-optimism-node = { git = "https://github.com/paradigmxyz/reth.git", rev = "6d3aa5a", features = [ 90 | "optimism", 91 | ] } 92 | reth-optimism-cli = { git = "https://github.com/paradigmxyz/reth.git", rev = "6d3aa5a", features = [ 93 | "optimism", 94 | ] } 95 | reth-optimism-rpc = { git = "https://github.com/paradigmxyz/reth.git", rev = "6d3aa5a", features = [ 96 | "optimism", 97 | ] } 98 | reth-optimism-forks = { git = "https://github.com/paradigmxyz/reth.git", rev = "6d3aa5a" } 99 | reth-optimism-chainspec = { git = "https://github.com/paradigmxyz/reth.git", rev = "6d3aa5a" } 100 | reth-payload-builder = { git = "https://github.com/paradigmxyz/reth.git", rev = "6d3aa5a" } 101 | reth-primitives = { git = "https://github.com/paradigmxyz/reth.git", rev = "6d3aa5a", features = [ 102 | "optimism", 103 | ] } 104 | reth-provider = { git = "https://github.com/paradigmxyz/reth.git", rev = "6d3aa5a", features = [ 105 | "optimism", 106 | ] } 107 | reth-revm = { git = "https://github.com/paradigmxyz/reth.git", rev = "6d3aa5a", features = [ 108 | "optimism", 109 | ] } 110 | reth-storage-api = { git = "https://github.com/paradigmxyz/reth.git", rev = "6d3aa5a" } 111 | reth-tracing = { git = "https://github.com/paradigmxyz/reth.git", rev = "6d3aa5a" } 112 | reth-transaction-pool = { git = "https://github.com/paradigmxyz/reth.git", rev = "6d3aa5a" } 113 | reth-network = { git = "https://github.com/paradigmxyz/reth.git", rev = "6d3aa5a" } 114 | reth-network-types = { git = "https://github.com/paradigmxyz/reth.git", rev = "6d3aa5a" } 115 | 116 | # rpc 117 | jsonrpsee = "0.24" 118 | 119 | # misc 120 | clap = "4" 121 | eyre = "0.6.12" 122 | tracing = "0.1.0" 123 | serde = "1" 124 | serde_json = "1" 125 | once_cell = "1.19" 126 | thiserror = "1" 127 | 128 | # misc-testing 129 | rstest = "0.18.2" 130 | -------------------------------------------------------------------------------- /Cross.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | pre-build = [ 3 | # rust-bindgen dependencies: llvm-dev libclang-dev (>= 5.0) clang (>= 5.0) 4 | "apt-get update && apt-get install --assume-yes --no-install-recommends llvm-dev libclang-6.0-dev clang-6.0" 5 | ] 6 | 7 | [build.env] 8 | passthrough = [ 9 | "JEMALLOC_SYS_WITH_LG_PAGE", 10 | ] 11 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM lukemathwalker/cargo-chef:latest-rust-1 AS chef 2 | WORKDIR /app 3 | 4 | LABEL org.opencontainers.image.source=https://github.com/paradigmxyz/alphanet 5 | LABEL org.opencontainers.image.licenses="MIT OR Apache-2.0" 6 | 7 | # Builds a cargo-chef plan 8 | FROM chef AS planner 9 | COPY . . 10 | RUN cargo chef prepare --recipe-path recipe.json 11 | 12 | FROM chef AS builder 13 | COPY --from=planner /app/recipe.json recipe.json 14 | 15 | # Build profile, release by default 16 | ARG BUILD_PROFILE=release 17 | ENV BUILD_PROFILE $BUILD_PROFILE 18 | 19 | # Extra Cargo features 20 | ARG FEATURES="" 21 | ENV FEATURES $FEATURES 22 | 23 | # Install system dependencies 24 | RUN apt-get update && apt-get -y upgrade && apt-get install -y libclang-dev pkg-config 25 | 26 | # Builds dependencies 27 | RUN cargo chef cook --profile $BUILD_PROFILE --recipe-path recipe.json 28 | 29 | # Build application 30 | COPY . . 31 | RUN cargo build --profile $BUILD_PROFILE --features "$FEATURES" --locked --bin alphanet 32 | 33 | # ARG is not resolved in COPY so we have to hack around it by copying the 34 | # binary to a temporary location 35 | RUN cp /app/target/$BUILD_PROFILE/alphanet /app/alphanet 36 | 37 | # Use Ubuntu as the release image 38 | FROM ubuntu AS runtime 39 | WORKDIR /app 40 | 41 | # Copy alphanet over from the build stage 42 | COPY --from=builder /app/alphanet /usr/local/bin 43 | 44 | # Copy licenses 45 | COPY LICENSE-* ./ 46 | 47 | # Copy the genesis files 48 | ADD etc/dev-genesis.json ./etc/dev-genesis.json 49 | ADD etc/alphanet-genesis.json ./etc/alphanet-genesis.json 50 | 51 | EXPOSE 30303 30303/udp 9001 8545 9000 8546 52 | ENTRYPOINT ["/usr/local/bin/alphanet"] 53 | -------------------------------------------------------------------------------- /Dockerfile.cross: -------------------------------------------------------------------------------- 1 | # This image is meant to enable cross-architecture builds. 2 | # It assumes the reth binary has already been compiled for `$TARGETPLATFORM` and is 3 | # locatable in `./dist/bin/$TARGETARCH` 4 | FROM --platform=$TARGETPLATFORM ubuntu:22.04 5 | 6 | LABEL org.opencontainers.image.source=https://github.com/paradigmxyz/alphanet 7 | LABEL org.opencontainers.image.licenses="MIT OR Apache-2.0" 8 | 9 | # Filled by docker buildx 10 | ARG TARGETARCH 11 | 12 | COPY ./dist/bin/$TARGETARCH/alphanet /usr/local/bin/alphanet 13 | ADD ./etc/alphanet-genesis.json /etc/alphanet-genesis.json 14 | 15 | EXPOSE 30303 30303/udp 9001 8545 8546 9000 16 | ENTRYPOINT ["/usr/local/bin/alphanet", "--chain", "/etc/alphanet-genesis.json"] 17 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2022-2024 Reth Contributors 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2022-2024 Reth Contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Heavily inspired by Lighthouse: https://github.com/sigp/lighthouse/blob/693886b94176faa4cb450f024696cb69cda2fe58/Makefile 2 | # 3 | # and Reth: https://github.com/paradigmxyz/reth/blob/2e87b2a8d57813ce61f8898cf89d7b0dda2ab27d/Makefile 4 | .DEFAULT_GOAL := help 5 | 6 | GIT_TAG ?= $(shell git describe --tags --abbrev=0) 7 | BIN_DIR = "dist/bin" 8 | 9 | # Cargo profile for builds. Default is for local builds, CI uses an override. 10 | PROFILE ?= release 11 | 12 | # The docker image name 13 | DOCKER_IMAGE_NAME ?= ghcr.io/paradigmxyz/alphanet 14 | 15 | BUILD_PATH = "target" 16 | 17 | SOLIDITY_BUILD_IMAGE = "ghcr.io/paradigmxyz/foundry-alphanet@sha256:dec045ad42b69952cc02800bc8a749caaa899dbae5a73e31674d19cdb057dc14" 18 | 19 | # List of features to use when building. Can be overridden via the environment. 20 | # No jemalloc on Windows 21 | ifeq ($(OS),Windows_NT) 22 | FEATURES ?= 23 | else 24 | FEATURES ?= jemalloc asm-keccak 25 | endif 26 | 27 | ##@ Help 28 | 29 | .PHONY: help 30 | help: ## Display this help. 31 | @awk 'BEGIN {FS = ":.*##"; printf "Usage:\n make \033[36m\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST) 32 | 33 | .PHONY: build-eip3074-bytecode 34 | build-eip3074-bytecode: 35 | docker run --rm \ 36 | -v $$(pwd)/crates/testing/resources/eip3074:/app/foundry \ 37 | -u $$(id -u):$$(id -g) \ 38 | $(SOLIDITY_BUILD_IMAGE) \ 39 | --foundry-directory /app/foundry \ 40 | --foundry-command "forge build" 41 | 42 | .PHONY: check-eip3074-bytecode 43 | check-eip3074-bytecode: build-eip3074-bytecode 44 | @if ! git diff --exit-code --quiet; then \ 45 | echo "Error: There are uncommitted changes after the build. Please run 'make build-eip3074-bytecode' and commit the changes"; \ 46 | exit 1; \ 47 | fi 48 | 49 | .PHONY: build-bls12-381-bytecode 50 | build-bls12-381-bytecode: 51 | docker run --rm \ 52 | -v $$(pwd)/crates/testing/resources/bls12-381:/app/foundry \ 53 | -u $$(id -u):$$(id -g) \ 54 | $(SOLIDITY_BUILD_IMAGE) \ 55 | --foundry-directory /app/foundry \ 56 | --foundry-command "forge build" 57 | 58 | .PHONY: check-bls12-381-bytecode 59 | check-bls12-381-bytecode: build-bls12-381-bytecode 60 | @if ! git diff --exit-code --quiet; then \ 61 | echo "Error: There are uncommitted changes after the build. Please run 'make build-bls12-381-bytecode' and commit the changes"; \ 62 | exit 1; \ 63 | fi 64 | 65 | .PHONY: check-bytecode 66 | check-bytecode: check-eip3074-bytecode check-bls12-381-bytecode 67 | 68 | # The following commands use `cross` to build a cross-compile. 69 | # 70 | # These commands require that: 71 | # 72 | # - `cross` is installed (`cargo install cross`). 73 | # - Docker is running. 74 | # - The current user is in the `docker` group. 75 | # 76 | # The resulting binaries will be created in the `target/` directory. 77 | 78 | # For aarch64, disable asm-keccak optimizations and set the page size for 79 | # jemalloc. When cross compiling, we must compile jemalloc with a large page 80 | # size, otherwise it will use the current system's page size which may not work 81 | # on other systems. JEMALLOC_SYS_WITH_LG_PAGE=16 tells jemalloc to use 64-KiB 82 | # pages. See: https://github.com/paradigmxyz/reth/issues/6742 83 | build-aarch64-unknown-linux-gnu: FEATURES := $(filter-out asm-keccak,$(FEATURES)) 84 | build-aarch64-unknown-linux-gnu: export JEMALLOC_SYS_WITH_LG_PAGE=16 85 | 86 | # No jemalloc on Windows 87 | build-x86_64-pc-windows-gnu: FEATURES := $(filter-out jemalloc jemalloc-prof,$(FEATURES)) 88 | 89 | # Note: The additional rustc compiler flags are for intrinsics needed by MDBX. 90 | # See: https://github.com/cross-rs/cross/wiki/FAQ#undefined-reference-with-build-std 91 | build-%: 92 | RUSTFLAGS="-C link-arg=-lgcc -Clink-arg=-static-libgcc" \ 93 | cross build --bin alphanet --target $* --features "$(FEATURES)" --profile "$(PROFILE)" 94 | 95 | # Unfortunately we can't easily use cross to build for Darwin because of licensing issues. 96 | # If we wanted to, we would need to build a custom Docker image with the SDK available. 97 | # 98 | # Note: You must set `SDKROOT` and `MACOSX_DEPLOYMENT_TARGET`. These can be found using `xcrun`. 99 | # 100 | # `SDKROOT=$(xcrun -sdk macosx --show-sdk-path) MACOSX_DEPLOYMENT_TARGET=$(xcrun -sdk macosx --show-sdk-platform-version)` 101 | build-x86_64-apple-darwin: 102 | $(MAKE) build-native-x86_64-apple-darwin 103 | build-aarch64-apple-darwin: 104 | $(MAKE) build-native-aarch64-apple-darwin 105 | 106 | ##@ Docker 107 | 108 | # Note: This requires a buildx builder with emulation support. For example: 109 | # 110 | # `docker run --privileged --rm tonistiigi/binfmt --install amd64,arm64` 111 | # `docker buildx create --use --driver docker-container --name cross-builder` 112 | .PHONY: docker-build-push 113 | docker-build-push: ## Build and push a cross-arch Docker image tagged with the latest git tag. 114 | $(call docker_build_push,$(GIT_TAG),$(GIT_TAG)) 115 | 116 | # Note: This requires a buildx builder with emulation support. For example: 117 | # 118 | # `docker run --privileged --rm tonistiigi/binfmt --install amd64,arm64` 119 | # `docker buildx create --use --driver docker-container --name cross-builder` 120 | .PHONY: docker-build-push-latest 121 | docker-build-push-latest: ## Build and push a cross-arch Docker image tagged with the latest git tag and `latest`. 122 | $(call docker_build_push,$(GIT_TAG),latest) 123 | 124 | # Note: This requires a buildx builder with emulation support. For example: 125 | # 126 | # `docker run --privileged --rm tonistiigi/binfmt --install amd64,arm64` 127 | # `docker buildx create --use --name cross-builder` 128 | .PHONY: docker-build-push-nightly 129 | docker-build-push-nightly: ## Build and push cross-arch Docker image tagged with the latest git tag with a `-nightly` suffix, and `latest-nightly`. 130 | $(call docker_build_push,$(GIT_TAG)-nightly,latest-nightly) 131 | 132 | # Create a cross-arch Docker image with the given tags and push it 133 | define docker_build_push 134 | $(MAKE) build-x86_64-unknown-linux-gnu 135 | mkdir -p $(BIN_DIR)/amd64 136 | cp $(BUILD_PATH)/x86_64-unknown-linux-gnu/$(PROFILE)/alphanet $(BIN_DIR)/amd64/alphanet 137 | 138 | $(MAKE) build-aarch64-unknown-linux-gnu 139 | mkdir -p $(BIN_DIR)/arm64 140 | cp $(BUILD_PATH)/aarch64-unknown-linux-gnu/$(PROFILE)/alphanet $(BIN_DIR)/arm64/alphanet 141 | 142 | docker buildx build --file ./Dockerfile.cross . \ 143 | --platform linux/amd64,linux/arm64 \ 144 | --tag $(DOCKER_IMAGE_NAME):$(1) \ 145 | --tag $(DOCKER_IMAGE_NAME):$(2) \ 146 | --provenance=false \ 147 | --push 148 | endef 149 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # alphanet 2 | 3 | 4 | 5 | [![MIT License][mit-badge]][mit-url] 6 | [![Apache-2.0 License][apache-badge]][apache-url] 7 | [![CI Status][actions-badge]][actions-url] 8 | 9 | > [!IMPORTANT] 10 | > This repo has been moved to [Odyssey](https://github.com/ithacaxyz/odyssey) and is no longer being maintained. 11 | 12 | ## What is Reth AlphaNet? 13 | 14 | Reth AlphaNet is a testnet OP Stack rollup aimed at enabling experimentation of bleeding edge Ethereum Research. 15 | AlphaNet is __not__ a fork of reth. 16 | AlphaNet implements traits provided by the [reth node builder API](https://paradigmxyz.github.io/reth/docs/reth_node_builder/index.html), allowing implementation of precompiles and instructions of experimental EIPs without forking the node. 17 | 18 | Specifically, AlphaNet currently implements the following EIPs: 19 | - [EIP-7702](https://eips.ethereum.org/EIPS/eip-7702): Set EOA account code. 20 | - [EIP-7212](https://eips.ethereum.org/EIPS/eip-7212): Precompile for secp256r1 curve support. 21 | - [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537): Precompiles for BLS12-381 curve operations. 22 | 23 | AlphaNet also implements the EIPs for EOF, or [The EVM Object Format](https://evmobjectformat.org/). 24 | 25 | ### Why AlphaNet? 26 | 27 | AlphaNet has 2 goals: 28 | 1. Showcase Reth's performance at the extremes. We intend to launch a hosted version of AlphaNet on [Conduit](https://conduit.xyz/), targeting 50mgas/s, and eventually ramping up to 1ggas/s and beyond. In the process we hope to hit the state growth performance bottleneck, and discover ways to solve it. If our hosted chains end up getting too big, we may possibly restart the experiment from zero, and try again. 29 | 2. Showcase how Reth's modular architecture can serve as a distribution channel for research ideas. Specifically, 30 | AlphaNet's node extensions were chosen for their ability to enable applications that enhance the onchain user experience, and 31 | drastically reduce cost for existing applications that improve UX. 32 | 33 | ### AlphaNet Local Development 34 | 35 | AlphaNet does not yet have a running testnet, but can be run locally for development and testing purposes. To do this, the binary can be run with the `--dev` flag, which will start the node with a development configuration. 36 | 37 | First, alphanet should be built locally: 38 | ```bash 39 | git clone https://github.com/paradigmxyz/alphanet 40 | cd alphanet 41 | cargo install --path bin/alphanet 42 | ``` 43 | 44 | ```bash 45 | alphanet node --chain etc/alphanet-genesis.json --dev --http --http.api all 46 | ``` 47 | 48 | This will start the node with a development configuration, and expose the HTTP API on `http://localhost:8545`. 49 | 50 | To use EOF-enabled foundry, use [forge-eof](https://github.com/paradigmxyz/forge-eof) and follow installation instructions. 51 | 52 | ### Running AlphaNet 53 | 54 | > [!WARNING] 55 | > 56 | > AlphaNet does not yet have a running testnet, please use the local development instructions above! 57 | 58 | Running AlphaNet will require running additional infrastructure for the archival L1 node. These instructions are a guide for 59 | running the AlphaNet OP-stack node only. 60 | 61 | For instructions on running the full AlphaNet OP stack, including the L1 node, see the [Reth book section on running the OP stack](https://paradigmxyz.github.io/reth/run/optimism.html), using the `alphanet` binary instead of `op-reth`. 62 | 63 | #### Running the alphanet execution node 64 | 65 | To run AlphaNet from source, clone the repository and run the following commands: 66 | 67 | ```bash 68 | git clone https://github.com/paradigmxyz/alphanet.git 69 | cd alphanet 70 | cargo install --path bin/alphanet 71 | alphanet node 72 | --chain etc/alphanet-genesis.json \ 73 | --rollup.sequencer-http \ 74 | --http \ 75 | --ws \ 76 | --authrpc.port 9551 \ 77 | --authrpc.jwtsecret /path/to/jwt.hex 78 | ``` 79 | 80 | #### Running op-node with the alphanet configuration 81 | 82 | Once `alphanet` is started, [`op-node`](https://github.com/ethereum-optimism/optimism/tree/develop/op-node) can be run with the 83 | included `alphanet-rollup.json`: 84 | 85 | ```bash 86 | cd alphanet/ 87 | op-node \ 88 | --rollup.config ./etc/alphanet-rollup.json \ 89 | --l1= \ 90 | --l2=http://localhost:9551 \ 91 | --l2.jwt-secret=/path/to/jwt.hex \ 92 | --rpc.addr=0.0.0.0 \ 93 | --rpc.port=7000 \ 94 | --l1.trustrpc 95 | ``` 96 | 97 | ### Running AlphaNet with Kurtosis 98 | 99 | Running a local network with a full AlphaNet OP stack with Kurtosis requires some extra setup, since AlphaNet uses a forked version of `op-node`. 100 | 101 | To get started, follow [these instructions](https://docs.kurtosis.com/install/) to install Kurtosis. 102 | 103 | Next, clone and build the modified `optimism-contract-deployer` image: 104 | 105 | ```bash 106 | git clone git@github.com:paradigmxyz/optimism-package.git 107 | cd optimism-package 108 | git switch alphanet 109 | docker build . -t ethpandaops/optimism-contract-deployer:latest --progress plain 110 | ``` 111 | 112 | > [!NOTE] 113 | > 114 | > The image may fail to build if you have not allocated enough memory for Docker. 115 | 116 | Finally, run start a Kurtosis enclave (ensure you are still in `optimism-package`): 117 | 118 | ```bash 119 | kurtosis run --enclave op-devnet github.com/paradigmxyz/optimism-package@alphanet \ 120 | --args-file https://raw.githubusercontent.com/paradigmxyz/alphanet/main/etc/kurtosis.yaml 121 | ``` 122 | 123 | This will start an enclave named `op-devnet`. You can tear down the enclave with `kurtosis enclave rm --force op-devnet`, or tear down all enclaves using `kurtosis clean -a`. 124 | 125 | > [!NOTE] 126 | > 127 | > If you want to use a custom build of AlphaNet, simply build an AlphaNet image with `docker build . -t ghcr.io/paradigmxyz/alphanet:latest`. 128 | 129 | Consult the [Kurtosis OP package](https://github.com/ethpandaops/optimism-package) repository for instructions on how to adjust the args file to spin up additional services, like a block exporer. 130 | 131 | ### Security 132 | 133 | See [SECURITY.md](SECURITY.md). 134 | 135 | #### License 136 | 137 | 138 | Licensed under either of Apache License, Version 139 | 2.0 or MIT license at your option. 140 | 141 | 142 |
143 | 144 | 145 | Unless you explicitly state otherwise, any contribution intentionally submitted 146 | for inclusion in these crates by you, as defined in the Apache-2.0 license, 147 | shall be dual licensed as above, without any additional terms or conditions. 148 | 149 | 150 | 151 | 152 | 153 | [mit-badge]: https://img.shields.io/badge/license-MIT-blue.svg 154 | [apache-badge]: https://img.shields.io/badge/license-Apache--2.0-blue.svg 155 | [mit-url]: LICENSE-MIT 156 | [apache-url]: LICENSE-APACHE 157 | [actions-badge]: https://github.com/paradigmxyz/alphanet/workflows/unit/badge.svg 158 | [actions-url]: https://github.com/paradigmxyz/alphanet/actions?query=workflow%3ACI+branch%3Amain 159 | [foundry-alphanet]: https://github.com/paradigmxyz/foundry-alphanet 160 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Reporting a Vulnerability 4 | 5 | Contact georgios at paradigm.xyz. 6 | -------------------------------------------------------------------------------- /bin/alphanet/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "alphanet" 3 | version.workspace = true 4 | edition.workspace = true 5 | rust-version.workspace = true 6 | license.workspace = true 7 | repository.workspace = true 8 | description = "Reth AlphaNet is a testnet OP Stack rollup aimed at enabling experimentation of bleeding edge Ethereum Research." 9 | default-run = "alphanet" 10 | 11 | [lints] 12 | workspace = true 13 | 14 | [dependencies] 15 | alloy-signer-local.workspace = true 16 | alloy-network.workspace = true 17 | alloy-primitives.workspace = true 18 | alphanet-node.workspace = true 19 | alphanet-wallet.workspace = true 20 | eyre.workspace = true 21 | tracing.workspace = true 22 | reth-cli-util.workspace = true 23 | reth-node-builder.workspace = true 24 | reth-optimism-node.workspace = true 25 | reth-optimism-cli.workspace = true 26 | reth-optimism-rpc.workspace = true 27 | reth-provider.workspace = true 28 | clap = { workspace = true, features = ["derive"] } 29 | 30 | [features] 31 | default = ["jemalloc"] 32 | 33 | asm-keccak = ["reth-optimism-cli/asm-keccak"] 34 | 35 | jemalloc = ["reth-cli-util/jemalloc"] 36 | jemalloc-prof = ["jemalloc", "reth-cli-util/jemalloc-prof"] 37 | 38 | min-error-logs = ["tracing/release_max_level_error"] 39 | min-warn-logs = ["tracing/release_max_level_warn"] 40 | min-info-logs = ["tracing/release_max_level_info"] 41 | min-debug-logs = ["tracing/release_max_level_debug"] 42 | min-trace-logs = ["tracing/release_max_level_trace"] 43 | 44 | [[bin]] 45 | name = "alphanet" 46 | path = "src/main.rs" 47 | -------------------------------------------------------------------------------- /bin/alphanet/src/main.rs: -------------------------------------------------------------------------------- 1 | //! # Reth AlphaNet 2 | //! 3 | //! Reth AlphaNet is a testnet OP Stack rollup aimed at enabling experimentation of bleeding edge 4 | //! Ethereum Research. It aims to showcase how Reth's pluggable and modularized architecture can 5 | //! serve as a distribution channel for research ideas. 6 | //! 7 | //! ## Feature Flags 8 | //! 9 | //! - `jemalloc`: Uses [jemallocator](https://github.com/tikv/jemallocator) as the global allocator. 10 | //! This is **not recommended on Windows**. See [here](https://rust-lang.github.io/rfcs/1974-global-allocators.html#jemalloc) 11 | //! for more info. 12 | //! - `jemalloc-prof`: Enables [jemallocator's](https://github.com/tikv/jemallocator) heap profiling 13 | //! and leak detection functionality. See [jemalloc's opt.prof](https://jemalloc.net/jemalloc.3.html#opt.prof) 14 | //! documentation for usage details. This is **not recommended on Windows**. See [here](https://rust-lang.github.io/rfcs/1974-global-allocators.html#jemalloc) 15 | //! for more info. 16 | //! - `asm-keccak`: replaces the default, pure-Rust implementation of Keccak256 with one implemented 17 | //! in assembly; see [the `keccak-asm` crate](https://github.com/DaniPopes/keccak-asm) for more 18 | //! details and supported targets 19 | //! - `min-error-logs`: Disables all logs below `error` level. 20 | //! - `min-warn-logs`: Disables all logs below `warn` level. 21 | //! - `min-info-logs`: Disables all logs below `info` level. This can speed up the node, since fewer 22 | //! calls to the logging component is made. 23 | //! - `min-debug-logs`: Disables all logs below `debug` level. 24 | //! - `min-trace-logs`: Disables all logs below `trace` level. 25 | 26 | use alloy_network::EthereumWallet; 27 | use alloy_primitives::Address; 28 | use alloy_signer_local::PrivateKeySigner; 29 | use alphanet_node::{chainspec::AlphanetChainSpecParser, node::AlphaNetNode}; 30 | use alphanet_wallet::{AlphaNetWallet, AlphaNetWalletApiServer}; 31 | use clap::Parser; 32 | use eyre::Context; 33 | use reth_node_builder::{engine_tree_config::TreeConfig, EngineNodeLauncher}; 34 | use reth_optimism_cli::Cli; 35 | use reth_optimism_node::{args::RollupArgs, node::OptimismAddOns}; 36 | use reth_optimism_rpc::sequencer::SequencerClient; 37 | use reth_provider::providers::BlockchainProvider2; 38 | use tracing::{info, warn}; 39 | 40 | #[global_allocator] 41 | static ALLOC: reth_cli_util::allocator::Allocator = reth_cli_util::allocator::new_allocator(); 42 | 43 | #[doc(hidden)] 44 | fn main() { 45 | reth_cli_util::sigsegv_handler::install(); 46 | 47 | // Enable backtraces unless a RUST_BACKTRACE value has already been explicitly provided. 48 | if std::env::var_os("RUST_BACKTRACE").is_none() { 49 | std::env::set_var("RUST_BACKTRACE", "1"); 50 | } 51 | 52 | if let Err(err) = 53 | Cli::::parse().run(|builder, rollup_args| async move { 54 | let node = builder 55 | .with_types_and_provider::>() 56 | .with_components(AlphaNetNode::components(rollup_args.clone())) 57 | .with_add_ons(OptimismAddOns::new(rollup_args.sequencer_http.clone())) 58 | .extend_rpc_modules(move |ctx| { 59 | // register sequencer tx forwarder 60 | if let Some(sequencer_http) = rollup_args.sequencer_http.clone() { 61 | ctx.registry 62 | .eth_api() 63 | .set_sequencer_client(SequencerClient::new(sequencer_http))?; 64 | } 65 | 66 | // register alphanet wallet namespace 67 | if let Ok(sk) = std::env::var("EXP1_SK") { 68 | let signer: PrivateKeySigner = 69 | sk.parse().wrap_err("Invalid EXP0001 secret key.")?; 70 | let wallet = EthereumWallet::from(signer); 71 | 72 | let raw_delegations = std::env::var("EXP1_WHITELIST") 73 | .wrap_err("No EXP0001 delegations specified")?; 74 | let valid_delegations: Vec
= raw_delegations 75 | .split(',') 76 | .map(|addr| Address::parse_checksummed(addr, None)) 77 | .collect::>() 78 | .wrap_err("No valid EXP0001 delegations specified")?; 79 | 80 | ctx.modules.merge_configured( 81 | AlphaNetWallet::new( 82 | ctx.provider().clone(), 83 | wallet, 84 | ctx.registry.eth_api().clone(), 85 | ctx.config().chain.chain().id(), 86 | valid_delegations, 87 | ) 88 | .into_rpc(), 89 | )?; 90 | 91 | info!(target: "reth::cli", "EXP0001 wallet configured"); 92 | } else { 93 | warn!(target: "reth::cli", "EXP0001 wallet not configured"); 94 | } 95 | 96 | Ok(()) 97 | }) 98 | .launch_with_fn(|builder| { 99 | let engine_tree_config = TreeConfig::default() 100 | .with_persistence_threshold(rollup_args.persistence_threshold) 101 | .with_memory_block_buffer_target(rollup_args.memory_block_buffer_target); 102 | let launcher = EngineNodeLauncher::new( 103 | builder.task_executor().clone(), 104 | builder.config().datadir(), 105 | engine_tree_config, 106 | ); 107 | builder.launch_with(launcher) 108 | }) 109 | .await?; 110 | 111 | node.wait_for_node_exit().await 112 | }) 113 | { 114 | eprintln!("Error: {err:?}"); 115 | std::process::exit(1); 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /clippy.toml: -------------------------------------------------------------------------------- 1 | msrv = "1.81" 2 | allow-dbg-in-tests = true 3 | -------------------------------------------------------------------------------- /crates/node/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "alphanet-node" 3 | version.workspace = true 4 | edition.workspace = true 5 | rust-version.workspace = true 6 | authors.workspace = true 7 | license.workspace = true 8 | repository.workspace = true 9 | keywords.workspace = true 10 | categories.workspace = true 11 | 12 | [dependencies] 13 | alphanet-precompile.workspace = true 14 | once_cell.workspace = true 15 | reth-cli.workspace = true 16 | reth-node-api.workspace = true 17 | reth-node-builder.workspace = true 18 | reth-optimism-node.workspace = true 19 | reth-optimism-forks.workspace = true 20 | reth-optimism-chainspec.workspace = true 21 | reth-chainspec.workspace = true 22 | reth-payload-builder.workspace = true 23 | reth-primitives.workspace = true 24 | reth-revm.workspace = true 25 | reth-transaction-pool.workspace = true 26 | reth-network.workspace = true 27 | reth-network-types.workspace = true 28 | 29 | alloy-primitives.workspace = true 30 | 31 | serde_json.workspace = true 32 | 33 | eyre.workspace = true 34 | 35 | [lints] 36 | workspace = true 37 | -------------------------------------------------------------------------------- /crates/node/src/chainspec.rs: -------------------------------------------------------------------------------- 1 | //! Alphanet chainspec parsing logic. 2 | 3 | use alloy_primitives::{b256, U256}; 4 | use once_cell::sync::Lazy; 5 | use reth_chainspec::{ 6 | once_cell_set, BaseFeeParams, BaseFeeParamsKind, Chain, ChainHardforks, ChainSpec, 7 | EthereumHardfork, ForkCondition, NamedChain, 8 | }; 9 | use reth_cli::chainspec::{parse_genesis, ChainSpecParser}; 10 | use reth_optimism_chainspec::OpChainSpec; 11 | use reth_optimism_forks::OptimismHardfork; 12 | use reth_primitives::constants::ETHEREUM_BLOCK_GAS_LIMIT; 13 | use std::sync::Arc; 14 | 15 | /// Alphanet forks. 16 | pub static ALPHANET_FORKS: Lazy = Lazy::new(|| { 17 | ChainHardforks::new(vec![ 18 | (EthereumHardfork::Frontier.boxed(), ForkCondition::Block(0)), 19 | (EthereumHardfork::Homestead.boxed(), ForkCondition::Block(0)), 20 | (EthereumHardfork::Dao.boxed(), ForkCondition::Block(0)), 21 | (EthereumHardfork::Tangerine.boxed(), ForkCondition::Block(0)), 22 | (EthereumHardfork::SpuriousDragon.boxed(), ForkCondition::Block(0)), 23 | (EthereumHardfork::Byzantium.boxed(), ForkCondition::Block(0)), 24 | (EthereumHardfork::Constantinople.boxed(), ForkCondition::Block(0)), 25 | (EthereumHardfork::Petersburg.boxed(), ForkCondition::Block(0)), 26 | (EthereumHardfork::Istanbul.boxed(), ForkCondition::Block(0)), 27 | (EthereumHardfork::Berlin.boxed(), ForkCondition::Block(0)), 28 | (EthereumHardfork::London.boxed(), ForkCondition::Block(0)), 29 | ( 30 | EthereumHardfork::Paris.boxed(), 31 | ForkCondition::TTD { fork_block: None, total_difficulty: U256::ZERO }, 32 | ), 33 | (EthereumHardfork::Shanghai.boxed(), ForkCondition::Timestamp(0)), 34 | (EthereumHardfork::Cancun.boxed(), ForkCondition::Timestamp(0)), 35 | (OptimismHardfork::Regolith.boxed(), ForkCondition::Timestamp(0)), 36 | (OptimismHardfork::Bedrock.boxed(), ForkCondition::Block(0)), 37 | (OptimismHardfork::Ecotone.boxed(), ForkCondition::Timestamp(0)), 38 | (OptimismHardfork::Canyon.boxed(), ForkCondition::Timestamp(0)), 39 | (EthereumHardfork::Prague.boxed(), ForkCondition::Timestamp(0)), 40 | ]) 41 | }); 42 | 43 | /// Alphanet dev testnet specification. 44 | pub static ALPHANET_DEV: Lazy> = Lazy::new(|| { 45 | OpChainSpec::new(ChainSpec { 46 | chain: Chain::from_named(NamedChain::Alphanet), 47 | genesis: serde_json::from_str(include_str!("../../../etc/dev-genesis.json")) 48 | .expect("Can't deserialize alphanet genesis json"), 49 | paris_block_and_final_difficulty: Some((0, U256::from(0))), 50 | hardforks: ALPHANET_FORKS.clone(), 51 | base_fee_params: BaseFeeParamsKind::Constant(BaseFeeParams::ethereum()), 52 | deposit_contract: None, 53 | ..Default::default() 54 | }) 55 | .into() 56 | }); 57 | 58 | /// Alphanet main chain specification. 59 | pub static ALPHANET_MAINNET: Lazy> = Lazy::new(|| { 60 | OpChainSpec::new(ChainSpec { 61 | chain: Chain::from_named(NamedChain::Alphanet), 62 | // genesis contains empty alloc field because state at first bedrock block is imported 63 | // manually from trusted source 64 | genesis: serde_json::from_str(include_str!("../../../etc/alphanet-genesis.json")) 65 | .expect("Can't deserialize alphanet genesis json"), 66 | genesis_hash: once_cell_set(b256!( 67 | "2f980576711e3617a5e4d83dd539548ec0f7792007d505a3d2e9674833af2d7c" 68 | )), 69 | paris_block_and_final_difficulty: Some((0, U256::from(0))), 70 | hardforks: ALPHANET_FORKS.clone(), 71 | base_fee_params: BaseFeeParamsKind::Variable( 72 | vec![ 73 | (EthereumHardfork::London.boxed(), BaseFeeParams::optimism()), 74 | (OptimismHardfork::Canyon.boxed(), BaseFeeParams::optimism_canyon()), 75 | ] 76 | .into(), 77 | ), 78 | max_gas_limit: ETHEREUM_BLOCK_GAS_LIMIT, 79 | prune_delete_limit: 10000, 80 | ..Default::default() 81 | }) 82 | .into() 83 | }); 84 | 85 | /// Alphanet chain specification parser. 86 | #[derive(Debug, Clone, Default)] 87 | pub struct AlphanetChainSpecParser; 88 | 89 | impl ChainSpecParser for AlphanetChainSpecParser { 90 | type ChainSpec = OpChainSpec; 91 | 92 | const SUPPORTED_CHAINS: &'static [&'static str] = &["alphanet", "dev"]; 93 | 94 | fn parse(s: &str) -> eyre::Result> { 95 | Ok(match s { 96 | "alphanet" => ALPHANET_MAINNET.clone(), 97 | "dev" => ALPHANET_DEV.clone(), 98 | s => { 99 | let mut chainspec = OpChainSpec::from(parse_genesis(s)?); 100 | 101 | // NOTE(onbjerg): This is a temporary workaround until we figure out a better way to 102 | // activate Prague based on a custom fork name. Currently there does not seem to be 103 | // a good way to do it. 104 | chainspec 105 | .inner 106 | .hardforks 107 | .insert(EthereumHardfork::Prague, ForkCondition::Timestamp(0)); 108 | 109 | // NOTE(onbjerg): op-node will fetch the genesis block and check that the hash 110 | // matches whatever is in the L2 rollup config, which it will not when we activate 111 | // Prague, since the autogenerated genesis header will include a requests root of 112 | // `EMPTY_ROOT`. To circumvent this without modifying the OP stack genesis 113 | // generator, we simply remove the requests root manually here. 114 | let mut header = chainspec.genesis_header().clone(); 115 | header.requests_root = None; 116 | chainspec.inner.genesis_header = once_cell_set(header); 117 | 118 | Arc::new(chainspec) 119 | } 120 | }) 121 | } 122 | } 123 | 124 | #[cfg(test)] 125 | mod tests { 126 | use std::path::PathBuf; 127 | 128 | use super::AlphanetChainSpecParser; 129 | use reth_chainspec::EthereumHardforks; 130 | use reth_cli::chainspec::ChainSpecParser; 131 | use reth_optimism_forks::OptimismHardforks; 132 | 133 | #[test] 134 | fn chainspec_parser_adds_prague() { 135 | let mut chainspec_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); 136 | chainspec_path.push("../../etc/alphanet-genesis.json"); 137 | 138 | let chain_spec = AlphanetChainSpecParser::parse(&chainspec_path.to_string_lossy()) 139 | .expect("could not parse chainspec"); 140 | 141 | assert!(chain_spec.is_bedrock_active_at_block(0)); 142 | assert!( 143 | chain_spec.is_prague_active_at_timestamp(0), 144 | "prague should be active at timestamp 0" 145 | ); 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /crates/node/src/evm.rs: -------------------------------------------------------------------------------- 1 | //! # AlphaNet EVM configuration 2 | //! 3 | //! The [AlphaNetEvmConfig] type implements the [ConfigureEvm] and [ConfigureEvmEnv] traits, 4 | //! configuring the custom AlphaNet precompiles and instructions. 5 | //! 6 | //! These trait implementations allow for custom precompiles and instructions to be implemented and 7 | //! integrated in a reth node only with importing, without the need to fork the node or EVM 8 | //! implementation. 9 | //! 10 | //! This currently configures the instructions defined in [EIP3074-instructions](https://github.com/paradigmxyz/eip3074-instructions), and the 11 | //! precompiles defined by [`alphanet_precompile`]. 12 | 13 | use alloy_primitives::{Address, Bytes, TxKind, U256}; 14 | use alphanet_precompile::secp256r1; 15 | use reth_chainspec::{ChainSpec, EthereumHardfork, Head}; 16 | use reth_node_api::{ConfigureEvm, ConfigureEvmEnv, NextBlockEnvAttributes}; 17 | use reth_optimism_chainspec::OpChainSpec; 18 | use reth_optimism_forks::OptimismHardfork; 19 | use reth_primitives::{ 20 | revm_primitives::{CfgEnvWithHandlerCfg, TxEnv}, 21 | transaction::FillTxEnv, 22 | Header, TransactionSigned, 23 | }; 24 | use reth_revm::{ 25 | handler::register::EvmHandler, 26 | inspector_handle_register, 27 | precompile::PrecompileSpecId, 28 | primitives::{ 29 | AnalysisKind, BlobExcessGasAndPrice, BlockEnv, CfgEnv, Env, HandlerCfg, OptimismFields, 30 | SpecId, 31 | }, 32 | ContextPrecompiles, Database, Evm, EvmBuilder, GetInspector, 33 | }; 34 | use std::sync::Arc; 35 | 36 | /// Custom EVM configuration 37 | #[derive(Debug, Clone)] 38 | pub struct AlphaNetEvmConfig { 39 | chain_spec: Arc, 40 | } 41 | 42 | impl AlphaNetEvmConfig { 43 | /// Creates a new AlphaNet EVM configuration with the given chain spec. 44 | pub const fn new(chain_spec: Arc) -> Self { 45 | Self { chain_spec } 46 | } 47 | 48 | /// Sets the precompiles to the EVM handler 49 | /// 50 | /// This will be invoked when the EVM is created via [ConfigureEvm::evm] or 51 | /// [ConfigureEvm::evm_with_inspector] 52 | /// 53 | /// This will use the default mainnet precompiles and add additional precompiles. 54 | fn set_precompiles(handler: &mut EvmHandler<'_, EXT, DB>) 55 | where 56 | DB: Database, 57 | { 58 | // first we need the evm spec id, which determines the precompiles 59 | let spec_id = handler.cfg.spec_id; 60 | 61 | // install the precompiles 62 | handler.pre_execution.load_precompiles = Arc::new(move || { 63 | let mut loaded_precompiles: ContextPrecompiles = 64 | ContextPrecompiles::new(PrecompileSpecId::from_spec_id(spec_id)); 65 | 66 | loaded_precompiles.extend(secp256r1::precompiles()); 67 | 68 | loaded_precompiles 69 | }); 70 | } 71 | } 72 | 73 | impl ConfigureEvmEnv for AlphaNetEvmConfig { 74 | type Header = Header; 75 | 76 | fn fill_tx_env(&self, tx_env: &mut TxEnv, transaction: &TransactionSigned, sender: Address) { 77 | transaction.fill_tx_env(tx_env, sender); 78 | } 79 | 80 | fn fill_tx_env_system_contract_call( 81 | &self, 82 | env: &mut Env, 83 | caller: Address, 84 | contract: Address, 85 | data: Bytes, 86 | ) { 87 | env.tx = TxEnv { 88 | caller, 89 | transact_to: TxKind::Call(contract), 90 | // Explicitly set nonce to None so revm does not do any nonce checks 91 | nonce: None, 92 | gas_limit: 30_000_000, 93 | value: U256::ZERO, 94 | data, 95 | // Setting the gas price to zero enforces that no value is transferred as part of the 96 | // call, and that the call will not count against the block's gas limit 97 | gas_price: U256::ZERO, 98 | // The chain ID check is not relevant here and is disabled if set to None 99 | chain_id: None, 100 | // Setting the gas priority fee to None ensures the effective gas price is derived from 101 | // the `gas_price` field, which we need to be zero 102 | gas_priority_fee: None, 103 | access_list: Vec::new(), 104 | // blob fields can be None for this tx 105 | blob_hashes: Vec::new(), 106 | max_fee_per_blob_gas: None, 107 | authorization_list: None, 108 | optimism: OptimismFields { 109 | source_hash: None, 110 | mint: None, 111 | is_system_transaction: Some(false), 112 | // The L1 fee is not charged for the EIP-4788 transaction, submit zero bytes for the 113 | // enveloped tx size. 114 | enveloped_tx: Some(Bytes::default()), 115 | }, 116 | }; 117 | 118 | // ensure the block gas limit is >= the tx 119 | env.block.gas_limit = U256::from(env.tx.gas_limit); 120 | 121 | // disable the base fee check for this call by setting the base fee to zero 122 | env.block.basefee = U256::ZERO; 123 | } 124 | 125 | fn fill_cfg_env( 126 | &self, 127 | cfg_env: &mut CfgEnvWithHandlerCfg, 128 | header: &Header, 129 | total_difficulty: U256, 130 | ) { 131 | let spec_id = revm_spec( 132 | &self.chain_spec, 133 | &Head { 134 | number: header.number, 135 | timestamp: header.timestamp, 136 | difficulty: header.difficulty, 137 | total_difficulty, 138 | hash: Default::default(), 139 | }, 140 | ); 141 | 142 | cfg_env.chain_id = self.chain_spec.chain().id(); 143 | cfg_env.perf_analyse_created_bytecodes = AnalysisKind::Analyse; 144 | 145 | cfg_env.handler_cfg.spec_id = spec_id; 146 | cfg_env.handler_cfg.is_optimism = true; 147 | } 148 | 149 | fn fill_block_env(&self, block_env: &mut BlockEnv, header: &Self::Header, after_merge: bool) { 150 | block_env.number = U256::from(header.number); 151 | block_env.coinbase = header.beneficiary; 152 | block_env.timestamp = U256::from(header.timestamp); 153 | if after_merge { 154 | block_env.prevrandao = Some(header.mix_hash); 155 | block_env.difficulty = U256::ZERO; 156 | } else { 157 | block_env.difficulty = header.difficulty; 158 | block_env.prevrandao = None; 159 | } 160 | block_env.basefee = U256::from(header.base_fee_per_gas.unwrap_or_default()); 161 | block_env.gas_limit = U256::from(header.gas_limit); 162 | 163 | // EIP-4844 excess blob gas of this block, introduced in Cancun 164 | if let Some(excess_blob_gas) = header.excess_blob_gas { 165 | block_env.set_blob_excess_gas_and_price(excess_blob_gas); 166 | } 167 | } 168 | 169 | fn next_cfg_and_block_env( 170 | &self, 171 | parent: &Self::Header, 172 | attributes: NextBlockEnvAttributes, 173 | ) -> (CfgEnvWithHandlerCfg, BlockEnv) { 174 | // configure evm env based on parent block 175 | let cfg = CfgEnv::default().with_chain_id(self.chain_spec.chain().id()); 176 | 177 | // ensure we're not missing any timestamp based hardforks 178 | let spec_id = revm_spec( 179 | &self.chain_spec, 180 | &Head { 181 | number: parent.number + 1, 182 | timestamp: attributes.timestamp, 183 | ..Default::default() 184 | }, 185 | ); 186 | 187 | // if the parent block did not have excess blob gas (i.e. it was pre-cancun), but it is 188 | // cancun now, we need to set the excess blob gas to the default value 189 | let blob_excess_gas_and_price = parent 190 | .next_block_excess_blob_gas() 191 | .or_else(|| { 192 | if spec_id.is_enabled_in(SpecId::CANCUN) { 193 | // default excess blob gas is zero 194 | Some(0) 195 | } else { 196 | None 197 | } 198 | }) 199 | .map(BlobExcessGasAndPrice::new); 200 | 201 | let block_env = BlockEnv { 202 | number: U256::from(parent.number + 1), 203 | coinbase: attributes.suggested_fee_recipient, 204 | timestamp: U256::from(attributes.timestamp), 205 | difficulty: U256::ZERO, 206 | prevrandao: Some(attributes.prev_randao), 207 | gas_limit: U256::from(parent.gas_limit), 208 | // calculate basefee based on parent block's gas usage 209 | basefee: U256::from( 210 | parent 211 | .next_block_base_fee( 212 | self.chain_spec.base_fee_params_at_timestamp(attributes.timestamp), 213 | ) 214 | .unwrap_or_default(), 215 | ), 216 | // calculate excess gas based on parent block's blob gas usage 217 | blob_excess_gas_and_price, 218 | }; 219 | 220 | let cfg_with_handler_cfg; 221 | { 222 | cfg_with_handler_cfg = CfgEnvWithHandlerCfg { 223 | cfg_env: cfg, 224 | handler_cfg: HandlerCfg { spec_id, is_optimism: true }, 225 | }; 226 | } 227 | 228 | (cfg_with_handler_cfg, block_env) 229 | } 230 | } 231 | 232 | impl ConfigureEvm for AlphaNetEvmConfig { 233 | type DefaultExternalContext<'a> = (); 234 | 235 | fn evm(&self, db: DB) -> Evm<'_, Self::DefaultExternalContext<'_>, DB> { 236 | EvmBuilder::default() 237 | .with_db(db) 238 | .optimism() 239 | // add additional precompiles 240 | .append_handler_register(Self::set_precompiles) 241 | .build() 242 | } 243 | 244 | fn evm_with_inspector(&self, db: DB, inspector: I) -> Evm<'_, I, DB> 245 | where 246 | DB: Database, 247 | I: GetInspector, 248 | { 249 | EvmBuilder::default() 250 | .with_db(db) 251 | .with_external_context(inspector) 252 | .optimism() 253 | // add additional precompiles 254 | .append_handler_register(Self::set_precompiles) 255 | .append_handler_register(inspector_handle_register) 256 | .build() 257 | } 258 | 259 | fn default_external_context<'a>(&self) -> Self::DefaultExternalContext<'a> {} 260 | } 261 | 262 | /// Determine the revm spec ID from the current block and reth chainspec. 263 | fn revm_spec(chain_spec: &ChainSpec, block: &Head) -> reth_revm::primitives::SpecId { 264 | if chain_spec.fork(EthereumHardfork::Prague).active_at_head(block) { 265 | reth_revm::primitives::PRAGUE_EOF 266 | } else if chain_spec.fork(OptimismHardfork::Granite).active_at_head(block) { 267 | reth_revm::primitives::GRANITE 268 | } else if chain_spec.fork(OptimismHardfork::Fjord).active_at_head(block) { 269 | reth_revm::primitives::FJORD 270 | } else if chain_spec.fork(OptimismHardfork::Ecotone).active_at_head(block) { 271 | reth_revm::primitives::ECOTONE 272 | } else if chain_spec.fork(OptimismHardfork::Canyon).active_at_head(block) { 273 | reth_revm::primitives::CANYON 274 | } else if chain_spec.fork(OptimismHardfork::Regolith).active_at_head(block) { 275 | reth_revm::primitives::REGOLITH 276 | } else if chain_spec.fork(OptimismHardfork::Bedrock).active_at_head(block) { 277 | reth_revm::primitives::BEDROCK 278 | } else if chain_spec.fork(EthereumHardfork::Prague).active_at_head(block) { 279 | reth_revm::primitives::PRAGUE 280 | } else if chain_spec.fork(EthereumHardfork::Cancun).active_at_head(block) { 281 | reth_revm::primitives::CANCUN 282 | } else if chain_spec.fork(EthereumHardfork::Shanghai).active_at_head(block) { 283 | reth_revm::primitives::SHANGHAI 284 | } else if chain_spec.fork(EthereumHardfork::Paris).active_at_head(block) { 285 | reth_revm::primitives::MERGE 286 | } else if chain_spec.fork(EthereumHardfork::London).active_at_head(block) { 287 | reth_revm::primitives::LONDON 288 | } else if chain_spec.fork(EthereumHardfork::Berlin).active_at_head(block) { 289 | reth_revm::primitives::BERLIN 290 | } else if chain_spec.fork(EthereumHardfork::Istanbul).active_at_head(block) { 291 | reth_revm::primitives::ISTANBUL 292 | } else if chain_spec.fork(EthereumHardfork::Petersburg).active_at_head(block) { 293 | reth_revm::primitives::PETERSBURG 294 | } else if chain_spec.fork(EthereumHardfork::Byzantium).active_at_head(block) { 295 | reth_revm::primitives::BYZANTIUM 296 | } else if chain_spec.fork(EthereumHardfork::SpuriousDragon).active_at_head(block) { 297 | reth_revm::primitives::SPURIOUS_DRAGON 298 | } else if chain_spec.fork(EthereumHardfork::Tangerine).active_at_head(block) { 299 | reth_revm::primitives::TANGERINE 300 | } else if chain_spec.fork(EthereumHardfork::Homestead).active_at_head(block) { 301 | reth_revm::primitives::HOMESTEAD 302 | } else if chain_spec.fork(EthereumHardfork::Frontier).active_at_head(block) { 303 | reth_revm::primitives::FRONTIER 304 | } else { 305 | panic!( 306 | "invalid hardfork chainspec: expected at least one hardfork, got {:?}", 307 | chain_spec.hardforks 308 | ) 309 | } 310 | } 311 | 312 | #[cfg(test)] 313 | mod tests { 314 | use super::*; 315 | use reth_chainspec::{Chain, ChainSpecBuilder, EthereumHardfork}; 316 | use reth_primitives::{ 317 | revm_primitives::{BlockEnv, CfgEnv, SpecId}, 318 | ForkCondition, 319 | }; 320 | 321 | #[test] 322 | fn test_fill_cfg_and_block_env() { 323 | let mut cfg_env = CfgEnvWithHandlerCfg::new_with_spec_id(CfgEnv::default(), SpecId::LATEST); 324 | let mut block_env = BlockEnv::default(); 325 | let header = Header::default(); 326 | let chain_spec = Arc::new(OpChainSpec::new( 327 | ChainSpecBuilder::default() 328 | .chain(Chain::optimism_mainnet()) 329 | .genesis(Default::default()) 330 | .with_fork(EthereumHardfork::Frontier, ForkCondition::Block(0)) 331 | .build(), 332 | )); 333 | let total_difficulty = U256::ZERO; 334 | 335 | AlphaNetEvmConfig::new(chain_spec.clone()).fill_cfg_and_block_env( 336 | &mut cfg_env, 337 | &mut block_env, 338 | &header, 339 | total_difficulty, 340 | ); 341 | 342 | assert_eq!(cfg_env.chain_id, chain_spec.chain().id()); 343 | } 344 | } 345 | -------------------------------------------------------------------------------- /crates/node/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Standalone crate for AlphaNet's node configuration and builder types. 2 | //! 3 | //! This contains mainly two types, [AlphaNetNode](node::AlphaNetNode) and 4 | //! [AlphaNetEvmConfig](evm::AlphaNetEvmConfig). 5 | //! 6 | //! The [AlphaNetNode](node::AlphaNetNode) type implements the 7 | //! [NodeTypes](reth_node_builder::NodeTypes) trait, and configures the engine types required for 8 | //! the optimism engine API. 9 | //! 10 | //! The [AlphaNetEvmConfig](evm::AlphaNetEvmConfig) type implements the 11 | //! [ConfigureEvm](reth_node_api::ConfigureEvm) and 12 | //! [ConfigureEvmEnv](reth_node_api::ConfigureEvmEnv) traits, configuring the custom AlphaNet 13 | //! precompiles and instructions. 14 | 15 | #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] 16 | #![warn(unused_crate_dependencies)] 17 | 18 | pub mod chainspec; 19 | pub mod evm; 20 | pub mod node; 21 | -------------------------------------------------------------------------------- /crates/node/src/node.rs: -------------------------------------------------------------------------------- 1 | //! # AlphaNet Node types configuration 2 | //! 3 | //! The [AlphaNetNode] type implements the [NodeTypes] trait, and configures the engine types 4 | //! required for the optimism engine API. 5 | 6 | use crate::evm::AlphaNetEvmConfig; 7 | use reth_network::{ 8 | transactions::{TransactionPropagationMode, TransactionsManagerConfig}, 9 | NetworkHandle, NetworkManager, 10 | }; 11 | use reth_network_types::ReputationChangeWeights; 12 | use reth_node_api::{FullNodeTypes, NodeTypesWithEngine}; 13 | use reth_node_builder::{ 14 | components::{ 15 | ComponentsBuilder, ExecutorBuilder, NetworkBuilder, PayloadServiceBuilder, 16 | PoolBuilderConfigOverrides, 17 | }, 18 | BuilderContext, Node, NodeTypes, 19 | }; 20 | use reth_optimism_chainspec::OpChainSpec; 21 | use reth_optimism_node::{ 22 | args::RollupArgs, 23 | node::{ 24 | OptimismAddOns, OptimismConsensusBuilder, OptimismEngineValidatorBuilder, 25 | OptimismNetworkBuilder, OptimismPayloadBuilder, OptimismPoolBuilder, 26 | }, 27 | OpExecutorProvider, OptimismEngineTypes, 28 | }; 29 | use reth_payload_builder::PayloadBuilderHandle; 30 | use reth_transaction_pool::{SubPoolLimit, TransactionPool, TXPOOL_MAX_ACCOUNT_SLOTS_PER_SENDER}; 31 | use std::time::Duration; 32 | 33 | /// Type configuration for a regular AlphaNet node. 34 | #[derive(Debug, Clone, Default)] 35 | pub struct AlphaNetNode { 36 | /// Additional Optimism args 37 | pub args: RollupArgs, 38 | } 39 | 40 | impl AlphaNetNode { 41 | /// Creates a new instance of the Optimism node type. 42 | pub const fn new(args: RollupArgs) -> Self { 43 | Self { args } 44 | } 45 | 46 | /// Returns the components for the given [RollupArgs]. 47 | pub fn components( 48 | args: RollupArgs, 49 | ) -> ComponentsBuilder< 50 | Node, 51 | OptimismPoolBuilder, 52 | AlphaNetPayloadBuilder, 53 | AlphanetNetworkBuilder, 54 | AlphaNetExecutorBuilder, 55 | OptimismConsensusBuilder, 56 | OptimismEngineValidatorBuilder, 57 | > 58 | where 59 | Node: FullNodeTypes< 60 | Types: NodeTypesWithEngine, 61 | >, 62 | { 63 | let RollupArgs { disable_txpool_gossip, compute_pending_block, discovery_v4, .. } = args; 64 | ComponentsBuilder::default() 65 | .node_types::() 66 | .pool(OptimismPoolBuilder { 67 | pool_config_overrides: PoolBuilderConfigOverrides { 68 | queued_limit: Some(SubPoolLimit::default() * 2), 69 | pending_limit: Some(SubPoolLimit::default() * 2), 70 | basefee_limit: Some(SubPoolLimit::default() * 2), 71 | max_account_slots: Some(TXPOOL_MAX_ACCOUNT_SLOTS_PER_SENDER * 2), 72 | ..Default::default() 73 | }, 74 | }) 75 | .payload(AlphaNetPayloadBuilder::new(compute_pending_block)) 76 | .network(AlphanetNetworkBuilder::new(OptimismNetworkBuilder { 77 | disable_txpool_gossip, 78 | disable_discovery_v4: !discovery_v4, 79 | })) 80 | .executor(AlphaNetExecutorBuilder::default()) 81 | .consensus(OptimismConsensusBuilder::default()) 82 | .engine_validator(OptimismEngineValidatorBuilder::default()) 83 | } 84 | } 85 | 86 | /// Configure the node types 87 | impl NodeTypes for AlphaNetNode { 88 | type Primitives = (); 89 | type ChainSpec = OpChainSpec; 90 | } 91 | 92 | impl NodeTypesWithEngine for AlphaNetNode { 93 | type Engine = OptimismEngineTypes; 94 | } 95 | 96 | impl Node for AlphaNetNode 97 | where 98 | N: FullNodeTypes< 99 | Types: NodeTypesWithEngine, 100 | >, 101 | { 102 | type ComponentsBuilder = ComponentsBuilder< 103 | N, 104 | OptimismPoolBuilder, 105 | AlphaNetPayloadBuilder, 106 | AlphanetNetworkBuilder, 107 | AlphaNetExecutorBuilder, 108 | OptimismConsensusBuilder, 109 | OptimismEngineValidatorBuilder, 110 | >; 111 | 112 | type AddOns = OptimismAddOns; 113 | 114 | fn components_builder(&self) -> Self::ComponentsBuilder { 115 | let Self { args } = self; 116 | Self::components(args.clone()) 117 | } 118 | 119 | fn add_ons(&self) -> Self::AddOns { 120 | OptimismAddOns::new(self.args.sequencer_http.clone()) 121 | } 122 | } 123 | 124 | /// The AlphaNet evm and executor builder. 125 | #[derive(Debug, Default, Clone, Copy)] 126 | #[non_exhaustive] 127 | pub struct AlphaNetExecutorBuilder; 128 | 129 | impl ExecutorBuilder for AlphaNetExecutorBuilder 130 | where 131 | Node: FullNodeTypes>, 132 | { 133 | type EVM = AlphaNetEvmConfig; 134 | type Executor = OpExecutorProvider; 135 | 136 | async fn build_evm( 137 | self, 138 | ctx: &BuilderContext, 139 | ) -> eyre::Result<(Self::EVM, Self::Executor)> { 140 | let chain_spec = ctx.chain_spec(); 141 | let evm_config = AlphaNetEvmConfig::new(chain_spec.clone()); 142 | let executor = OpExecutorProvider::new(chain_spec, evm_config.clone()); 143 | 144 | Ok((evm_config, executor)) 145 | } 146 | } 147 | 148 | /// The AlphaNet payload service builder. 149 | /// 150 | /// This service wraps the default Optimism payload builder, but replaces the default evm config 151 | /// with AlphaNet's own. 152 | #[derive(Debug, Default, Clone)] 153 | pub struct AlphaNetPayloadBuilder { 154 | /// Inner Optimism payload builder service. 155 | inner: OptimismPayloadBuilder, 156 | } 157 | 158 | impl AlphaNetPayloadBuilder { 159 | /// Create a new instance with the given `compute_pending_block` flag. 160 | pub const fn new(compute_pending_block: bool) -> Self { 161 | Self { inner: OptimismPayloadBuilder::new(compute_pending_block) } 162 | } 163 | } 164 | 165 | impl PayloadServiceBuilder for AlphaNetPayloadBuilder 166 | where 167 | Node: FullNodeTypes< 168 | Types: NodeTypesWithEngine, 169 | >, 170 | Pool: TransactionPool + Unpin + 'static, 171 | { 172 | async fn spawn_payload_service( 173 | self, 174 | ctx: &BuilderContext, 175 | pool: Pool, 176 | ) -> eyre::Result> { 177 | self.inner.spawn(AlphaNetEvmConfig::new(ctx.chain_spec().clone()), ctx, pool) 178 | } 179 | } 180 | 181 | /// The default alphanet network builder. 182 | #[derive(Debug, Default, Clone)] 183 | pub struct AlphanetNetworkBuilder { 184 | inner: OptimismNetworkBuilder, 185 | } 186 | 187 | impl AlphanetNetworkBuilder { 188 | /// Create a new instance based on the given op builder 189 | pub const fn new(network: OptimismNetworkBuilder) -> Self { 190 | Self { inner: network } 191 | } 192 | } 193 | 194 | impl NetworkBuilder for AlphanetNetworkBuilder 195 | where 196 | Node: FullNodeTypes>, 197 | Pool: TransactionPool + Unpin + 'static, 198 | { 199 | async fn build_network( 200 | self, 201 | ctx: &BuilderContext, 202 | pool: Pool, 203 | ) -> eyre::Result { 204 | let mut network_config = self.inner.network_config(ctx)?; 205 | // this is rolled with limited trusted peers and we want ignore any reputation slashing 206 | network_config.peers_config.reputation_weights = ReputationChangeWeights::zero(); 207 | network_config.peers_config.backoff_durations.low = Duration::from_secs(5); 208 | network_config.peers_config.backoff_durations.medium = Duration::from_secs(5); 209 | network_config.peers_config.max_backoff_count = u8::MAX; 210 | network_config.sessions_config.session_command_buffer = 500; 211 | network_config.sessions_config.session_event_buffer = 500; 212 | 213 | let txconfig = TransactionsManagerConfig { 214 | propagation_mode: TransactionPropagationMode::All, 215 | ..network_config.transactions_manager_config.clone() 216 | }; 217 | let network = NetworkManager::builder(network_config).await?; 218 | let handle = ctx.start_network_with(network, pool, txconfig); 219 | 220 | Ok(handle) 221 | } 222 | } 223 | -------------------------------------------------------------------------------- /crates/precompile/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "alphanet-precompile" 3 | version.workspace = true 4 | edition.workspace = true 5 | rust-version.workspace = true 6 | authors.workspace = true 7 | license.workspace = true 8 | repository.workspace = true 9 | keywords.workspace = true 10 | categories.workspace = true 11 | 12 | [dependencies] 13 | reth-revm.workspace = true 14 | 15 | alloy-primitives.workspace = true 16 | 17 | p256 = { version = "0.13.2", features = ["ecdsa"] } 18 | 19 | [dev-dependencies] 20 | reth-node-api.workspace = true 21 | reth-primitives.workspace = true 22 | eyre.workspace = true 23 | rstest.workspace = true 24 | 25 | [lints] 26 | workspace = true 27 | -------------------------------------------------------------------------------- /crates/precompile/src/addresses.rs: -------------------------------------------------------------------------------- 1 | //! Constants for the addresses used for each of the precompiled contracts. 2 | 3 | pub(crate) const P256VERIFY_ADDRESS: u64 = 0x14; 4 | -------------------------------------------------------------------------------- /crates/precompile/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! # AlphaNet precompiles. 2 | //! 3 | //! Implementations of EVM precompiled contracts for AlphaNet. 4 | //! 5 | //! Alphanet currently implements the following EIPs, which define precompiles: 6 | //! - [EIP-7212](https://eips.ethereum.org/EIPS/eip-7212): Precompile for secp256r1 Curve Support. 7 | //! The precompile implementation is located in the [secp256r1] module. 8 | 9 | #![cfg_attr(not(test), warn(unused_crate_dependencies))] 10 | 11 | /// The implementation of [EIP-7212](https://eips.ethereum.org/EIPS/eip-7212): Precompile for secp256r1 Curve Support. 12 | pub mod secp256r1; 13 | 14 | mod addresses; 15 | -------------------------------------------------------------------------------- /crates/precompile/src/secp256r1.rs: -------------------------------------------------------------------------------- 1 | //! # EIP-7212 secp256r1 Precompile 2 | //! 3 | //! This module implements the [EIP-7212](https://eips.ethereum.org/EIPS/eip-7212) precompile for 4 | //! secp256r1 curve support. 5 | //! 6 | //! The main purpose of this precompile is to verify ECDSA signatures that use the secp256r1, or 7 | //! P256 elliptic curve. The [`P256VERIFY`](crate::secp256r1::P256VERIFY) const represents the 8 | //! implementation of this precompile, with the address that it is currently deployed at. 9 | //! 10 | //! The precompile can be inserted in a custom EVM like this: 11 | //! ``` 12 | //! use alloy_primitives::U256; 13 | //! use alphanet_precompile::secp256r1; 14 | //! use reth_node_api::{ConfigureEvm, ConfigureEvmEnv, NextBlockEnvAttributes}; 15 | //! use reth_primitives::{Header, TransactionSigned}; 16 | //! use reth_revm::{ 17 | //! precompile::{PrecompileSpecId, Precompiles}, 18 | //! primitives::{Address, BlockEnv, Bytes, CfgEnvWithHandlerCfg, Env, TxEnv}, 19 | //! ContextPrecompiles, Database, Evm, EvmBuilder, 20 | //! }; 21 | //! use std::sync::Arc; 22 | //! 23 | //! #[derive(Debug, Clone, Copy, Default)] 24 | //! #[non_exhaustive] 25 | //! struct AlphaNetEvmConfig; 26 | //! 27 | //! impl ConfigureEvm for AlphaNetEvmConfig { 28 | //! type DefaultExternalContext<'a> = (); 29 | //! 30 | //! fn evm(&self, db: DB) -> Evm<'_, (), DB> { 31 | //! EvmBuilder::default() 32 | //! .with_db(db) 33 | //! .append_handler_register(|handler| { 34 | //! let spec_id = handler.cfg.spec_id; 35 | //! handler.pre_execution.load_precompiles = Arc::new(move || { 36 | //! let mut loaded_precompiles: ContextPrecompiles = 37 | //! ContextPrecompiles::new(PrecompileSpecId::from_spec_id(spec_id)); 38 | //! loaded_precompiles.extend(secp256r1::precompiles()); 39 | //! 40 | //! loaded_precompiles 41 | //! }); 42 | //! }) 43 | //! .build() 44 | //! } 45 | //! 46 | //! fn default_external_context<'a>(&self) -> Self::DefaultExternalContext<'a> {} 47 | //! } 48 | //! 49 | //! impl ConfigureEvmEnv for AlphaNetEvmConfig { 50 | //! type Header = Header; 51 | //! 52 | //! fn fill_tx_env( 53 | //! &self, 54 | //! tx_env: &mut TxEnv, 55 | //! transaction: &TransactionSigned, 56 | //! sender: Address, 57 | //! ) { 58 | //! todo!() 59 | //! } 60 | //! 61 | //! fn fill_cfg_env(&self, _: &mut CfgEnvWithHandlerCfg, _: &reth_primitives::Header, _: U256) { 62 | //! todo!() 63 | //! } 64 | //! 65 | //! fn fill_block_env(&self, _: &mut BlockEnv, _: &Self::Header, _: bool) {} 66 | //! 67 | //! fn next_cfg_and_block_env( 68 | //! &self, 69 | //! _: &Self::Header, 70 | //! _: NextBlockEnvAttributes, 71 | //! ) -> (CfgEnvWithHandlerCfg, BlockEnv) { 72 | //! todo!() 73 | //! } 74 | //! 75 | //! fn fill_tx_env_system_contract_call(&self, _: &mut Env, _: Address, _: Address, _: Bytes) { 76 | //! todo!() 77 | //! } 78 | //! } 79 | //! ``` 80 | use crate::addresses::P256VERIFY_ADDRESS; 81 | use alloy_primitives::{Bytes, B256}; 82 | use p256::ecdsa::{signature::hazmat::PrehashVerifier, Signature, VerifyingKey}; 83 | use reth_revm::{ 84 | precompile::{u64_to_address, Precompile, PrecompileWithAddress}, 85 | primitives::{PrecompileError, PrecompileErrors, PrecompileOutput, PrecompileResult}, 86 | }; 87 | 88 | /// Base gas fee for secp256r1 p256verify operation. 89 | const P256VERIFY_BASE: u64 = 3_450; 90 | 91 | /// Returns the secp256r1 precompile with its address. 92 | pub fn precompiles() -> impl Iterator { 93 | [P256VERIFY].into_iter() 94 | } 95 | 96 | /// [EIP-7212](https://eips.ethereum.org/EIPS/eip-7212#specification) secp256r1 precompile. 97 | pub const P256VERIFY: PrecompileWithAddress = 98 | PrecompileWithAddress(u64_to_address(P256VERIFY_ADDRESS), Precompile::Standard(p256_verify)); 99 | 100 | /// secp256r1 precompile logic. It takes the input bytes sent to the precompile 101 | /// and the gas limit. The output represents the result of verifying the 102 | /// secp256r1 signature of the input. 103 | /// 104 | /// The input is encoded as follows: 105 | /// 106 | /// | signed message hash | r | s | public key x | public key y | 107 | /// | :-----------------: | :-: | :-: | :----------: | :----------: | 108 | /// | 32 | 32 | 32 | 32 | 32 | 109 | fn p256_verify(input: &Bytes, gas_limit: u64) -> PrecompileResult { 110 | if P256VERIFY_BASE > gas_limit { 111 | return Err(PrecompileErrors::Error(PrecompileError::OutOfGas)); 112 | } 113 | let result = verify_impl(input).is_some(); 114 | let out = PrecompileOutput::new(P256VERIFY_BASE, B256::with_last_byte(result as u8).into()); 115 | Ok(out) 116 | } 117 | 118 | /// Returns `Some(())` if the signature included in the input byte slice is 119 | /// valid, `None` otherwise. 120 | fn verify_impl(input: &[u8]) -> Option<()> { 121 | if input.len() < 160 { 122 | return None; 123 | } 124 | 125 | // msg signed (msg is already the hash of the original message) 126 | let msg: &[u8; 32] = input[..32].try_into().unwrap(); 127 | // r, s: signature 128 | let sig: &[u8; 64] = input[32..96].try_into().unwrap(); 129 | // x, y: public key 130 | let pk: &[u8; 64] = input[96..160].try_into().unwrap(); 131 | 132 | // append 0x04 to the public key: uncompressed form 133 | let mut uncompressed_pk = [0u8; 65]; 134 | uncompressed_pk[0] = 0x04; 135 | uncompressed_pk[1..].copy_from_slice(pk); 136 | 137 | // Can fail only if the input is not exact length. 138 | let signature = Signature::from_slice(sig).unwrap(); 139 | // Can fail if the input is not valid, so we have to propagate the error. 140 | let public_key = VerifyingKey::from_sec1_bytes(&uncompressed_pk).ok()?; 141 | 142 | public_key.verify_prehash(msg, &signature).ok() 143 | } 144 | 145 | #[cfg(test)] 146 | mod test { 147 | use super::*; 148 | use reth_revm::primitives::hex::FromHex; 149 | use rstest::rstest; 150 | 151 | #[rstest] 152 | // test vectors from https://github.com/daimo-eth/p256-verifier/tree/master/test-vectors 153 | #[case::ok_1("4cee90eb86eaa050036147a12d49004b6b9c72bd725d39d4785011fe190f0b4da73bd4903f0ce3b639bbbf6e8e80d16931ff4bcf5993d58468e8fb19086e8cac36dbcd03009df8c59286b162af3bd7fcc0450c9aa81be5d10d312af6c66b1d604aebd3099c618202fcfe16ae7770b0c49ab5eadf74b754204a3bb6060e44eff37618b065f9832de4ca6ca971a7a1adc826d0f7c00181a5fb2ddf79ae00b4e10e", true)] 154 | #[case::ok_2("3fec5769b5cf4e310a7d150508e82fb8e3eda1c2c94c61492d3bd8aea99e06c9e22466e928fdccef0de49e3503d2657d00494a00e764fd437bdafa05f5922b1fbbb77c6817ccf50748419477e843d5bac67e6a70e97dde5a57e0c983b777e1ad31a80482dadf89de6302b1988c82c29544c9c07bb910596158f6062517eb089a2f54c9a0f348752950094d3228d3b940258c75fe2a413cb70baa21dc2e352fc5", true)] 155 | #[case::ok_3("e775723953ead4a90411a02908fd1a629db584bc600664c609061f221ef6bf7c440066c8626b49daaa7bf2bcc0b74be4f7a1e3dcf0e869f1542fe821498cbf2de73ad398194129f635de4424a07ca715838aefe8fe69d1a391cfa70470795a80dd056866e6e1125aff94413921880c437c9e2570a28ced7267c8beef7e9b2d8d1547d76dfcf4bee592f5fefe10ddfb6aeb0991c5b9dbbee6ec80d11b17c0eb1a", true)] 156 | #[case::ok_4("b5a77e7a90aa14e0bf5f337f06f597148676424fae26e175c6e5621c34351955289f319789da424845c9eac935245fcddd805950e2f02506d09be7e411199556d262144475b1fa46ad85250728c600c53dfd10f8b3f4adf140e27241aec3c2da3a81046703fccf468b48b145f939efdbb96c3786db712b3113bb2488ef286cdcef8afe82d200a5bb36b5462166e8ce77f2d831a52ef2135b2af188110beaefb1", true)] 157 | #[case::ok_5("858b991cfd78f16537fe6d1f4afd10273384db08bdfc843562a22b0626766686f6aec8247599f40bfe01bec0e0ecf17b4319559022d4d9bf007fe929943004eb4866760dedf31b7c691f5ce665f8aae0bda895c23595c834fecc2390a5bcc203b04afcacbb4280713287a2d0c37e23f7513fab898f2c1fefa00ec09a924c335d9b629f1d4fb71901c3e59611afbfea354d101324e894c788d1c01f00b3c251b2", true)] 158 | #[case::fail_wrong_msg_1("3cee90eb86eaa050036147a12d49004b6b9c72bd725d39d4785011fe190f0b4da73bd4903f0ce3b639bbbf6e8e80d16931ff4bcf5993d58468e8fb19086e8cac36dbcd03009df8c59286b162af3bd7fcc0450c9aa81be5d10d312af6c66b1d604aebd3099c618202fcfe16ae7770b0c49ab5eadf74b754204a3bb6060e44eff37618b065f9832de4ca6ca971a7a1adc826d0f7c00181a5fb2ddf79ae00b4e10e", false)] 159 | #[case::fail_wrong_msg_2("afec5769b5cf4e310a7d150508e82fb8e3eda1c2c94c61492d3bd8aea99e06c9e22466e928fdccef0de49e3503d2657d00494a00e764fd437bdafa05f5922b1fbbb77c6817ccf50748419477e843d5bac67e6a70e97dde5a57e0c983b777e1ad31a80482dadf89de6302b1988c82c29544c9c07bb910596158f6062517eb089a2f54c9a0f348752950094d3228d3b940258c75fe2a413cb70baa21dc2e352fc5", false)] 160 | #[case::fail_wrong_msg_3("f775723953ead4a90411a02908fd1a629db584bc600664c609061f221ef6bf7c440066c8626b49daaa7bf2bcc0b74be4f7a1e3dcf0e869f1542fe821498cbf2de73ad398194129f635de4424a07ca715838aefe8fe69d1a391cfa70470795a80dd056866e6e1125aff94413921880c437c9e2570a28ced7267c8beef7e9b2d8d1547d76dfcf4bee592f5fefe10ddfb6aeb0991c5b9dbbee6ec80d11b17c0eb1a", false)] 161 | #[case::fail_wrong_msg_4("c5a77e7a90aa14e0bf5f337f06f597148676424fae26e175c6e5621c34351955289f319789da424845c9eac935245fcddd805950e2f02506d09be7e411199556d262144475b1fa46ad85250728c600c53dfd10f8b3f4adf140e27241aec3c2da3a81046703fccf468b48b145f939efdbb96c3786db712b3113bb2488ef286cdcef8afe82d200a5bb36b5462166e8ce77f2d831a52ef2135b2af188110beaefb1", false)] 162 | #[case::fail_wrong_msg_5("958b991cfd78f16537fe6d1f4afd10273384db08bdfc843562a22b0626766686f6aec8247599f40bfe01bec0e0ecf17b4319559022d4d9bf007fe929943004eb4866760dedf31b7c691f5ce665f8aae0bda895c23595c834fecc2390a5bcc203b04afcacbb4280713287a2d0c37e23f7513fab898f2c1fefa00ec09a924c335d9b629f1d4fb71901c3e59611afbfea354d101324e894c788d1c01f00b3c251b2", false)] 163 | #[case::fail_short_input_1("4cee90eb86eaa050036147a12d49004b6a", false)] 164 | #[case::fail_short_input_2("4cee90eb86eaa050036147a12d49004b6a958b991cfd78f16537fe6d1f4afd10273384db08bdfc843562a22b0626766686f6aec8247599f40bfe01bec0e0ecf17b4319559022d4d9bf007fe929943004eb4866760dedf319", false)] 165 | fn test_sig_verify(#[case] input: &str, #[case] expect_success: bool) { 166 | let input = Bytes::from_hex(input).unwrap(); 167 | let target_gas = 3_500u64; 168 | let PrecompileOutput { gas_used, bytes } = p256_verify(&input, target_gas).unwrap(); 169 | assert_eq!(gas_used, 3_450u64); 170 | let expected_result = B256::with_last_byte(expect_success as u8); 171 | assert_eq!(bytes, expected_result.to_vec()); 172 | } 173 | 174 | #[rstest] 175 | fn test_not_enough_gas_errors() { 176 | let input = Bytes::from_hex("4cee90eb86eaa050036147a12d49004b6b9c72bd725d39d4785011fe190f0b4da73bd4903f0ce3b639bbbf6e8e80d16931ff4bcf5993d58468e8fb19086e8cac36dbcd03009df8c59286b162af3bd7fcc0450c9aa81be5d10d312af6c66b1d604aebd3099c618202fcfe16ae7770b0c49ab5eadf74b754204a3bb6060e44eff37618b065f9832de4ca6ca971a7a1adc826d0f7c00181a5fb2ddf79ae00b4e10e").unwrap(); 177 | let target_gas = 2_500u64; 178 | let result = p256_verify(&input, target_gas); 179 | 180 | assert!(result.is_err()); 181 | assert_eq!(result.err(), Some(PrecompileErrors::Error(PrecompileError::OutOfGas))); 182 | } 183 | 184 | #[rstest] 185 | #[case::ok_1("b5a77e7a90aa14e0bf5f337f06f597148676424fae26e175c6e5621c34351955289f319789da424845c9eac935245fcddd805950e2f02506d09be7e411199556d262144475b1fa46ad85250728c600c53dfd10f8b3f4adf140e27241aec3c2da3a81046703fccf468b48b145f939efdbb96c3786db712b3113bb2488ef286cdcef8afe82d200a5bb36b5462166e8ce77f2d831a52ef2135b2af188110beaefb1", true)] 186 | #[case::fail_1("b5a77e7a90aa14e0bf5f337f06f597148676424fae26e175c6e5621c34351955289f319789da424845c9eac935245fcddd805950e2f02506d09be7e411199556d262144475b1fa46ad85250728c600c53dfd10f8b3f4adf140e27241aec3c2daaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaef8afe82d200a5bb36b5462166e8ce77f2d831a52ef2135b2af188110beaefb1", false)] 187 | fn test_verify_impl(#[case] input: &str, #[case] expect_success: bool) { 188 | let input = Bytes::from_hex(input).unwrap(); 189 | let result = verify_impl(&input); 190 | 191 | assert_eq!(result.is_some(), expect_success); 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /crates/testing/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "alphanet-testing" 3 | version.workspace = true 4 | edition.workspace = true 5 | rust-version.workspace = true 6 | authors.workspace = true 7 | license.workspace = true 8 | repository.workspace = true 9 | keywords.workspace = true 10 | categories.workspace = true 11 | 12 | [dev-dependencies] 13 | alphanet-node.workspace = true 14 | 15 | alloy.workspace = true 16 | alloy-network.workspace = true 17 | alloy-signer-local = { workspace = true, features = ["mnemonic"] } 18 | 19 | reth = { workspace = true } 20 | reth-node-core = { workspace = true } 21 | reth-node-builder = { workspace = true, features = ["test-utils"] } 22 | reth-primitives.workspace = true 23 | reth-tracing.workspace = true 24 | 25 | once_cell = "1.19.0" 26 | tokio.workspace = true 27 | url = "2.5.0" 28 | 29 | [lints] 30 | workspace = true 31 | -------------------------------------------------------------------------------- /crates/testing/resources/eip3074/foundry.toml: -------------------------------------------------------------------------------- 1 | [profile.default] 2 | src = "src" 3 | out = "out" 4 | libs = ["lib"] 5 | remappings = [ 6 | "forge-std/=lib/forge-std/src/", 7 | ] 8 | prague = true -------------------------------------------------------------------------------- /crates/testing/resources/eip3074/out/BaseAuth.sol/BaseAuth.json: -------------------------------------------------------------------------------- 1 | {"abi":[{"type":"function","name":"getDigest","inputs":[{"name":"commit","type":"bytes32","internalType":"bytes32"},{"name":"nonce","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"digest","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"}],"bytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"deployedBytecode":{"object":"0x","sourceMap":"","linkReferences":{}},"methodIdentifiers":{"getDigest(bytes32,uint256)":"5bc928a7"},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.24-develop.2024.5.3+commit.187a178a\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"commit\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"name\":\"getDigest\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"digest\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"author\":\"Anna Carroll \",\"kind\":\"dev\",\"methods\":{\"getDigest(bytes32,uint256)\":{\"details\":\"signing `digest` authorizes this contact to execute code on behalf of the signer the logic of the inheriting contract should encode rules which respect the information within `commit`the authorizer includes `commit` in their signature to ensure the authorized contract will only execute intended actions(s). the Invoker logic MUST implement constraints on the contract execution based on information in the `commit`; otherwise, any EOA that signs an AUTH for the Invoker will be compromisedper EIP-3074, digest = keccak256(MAGIC || paddedChainId || paddedNonce || paddedInvokerAddress || commit)\",\"params\":{\"commit\":\"- any 32-byte value used to commit to transaction validity conditions\",\"nonce\":\"- signer's current nonce\"},\"returns\":{\"digest\":\"- sign the `digest` to authorize the invoker to execute the `calls`\"}}},\"title\":\"BaseAuth\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"getDigest(bytes32,uint256)\":{\"notice\":\"produce a digest for the authorizer to sign\"}},\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/BaseAuth.sol\":\"BaseAuth\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[\":forge-std/=lib/forge-std/src/\"]},\"sources\":{\"src/BaseAuth.sol\":{\"keccak256\":\"0x84e21d35b1a745c5d4798479ed22c16e8ae2f319de7c8f53c4eaa2fdca2b9dc7\",\"license\":\"UNLICENSED\",\"urls\":[\"bzz-raw://b89432fc50ffdd3d4a758d26a32ad744639159d8bd62338cea5ec5db1c9f3822\",\"dweb:/ipfs/QmaDY8DaGBVXApria5vt7biaPWrLMMDJTirenLfHifcyTV\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.24-develop.2024.5.3+commit.187a178a"},"language":"Solidity","output":{"abi":[{"inputs":[{"internalType":"bytes32","name":"commit","type":"bytes32"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"stateMutability":"view","type":"function","name":"getDigest","outputs":[{"internalType":"bytes32","name":"digest","type":"bytes32"}]}],"devdoc":{"kind":"dev","methods":{"getDigest(bytes32,uint256)":{"details":"signing `digest` authorizes this contact to execute code on behalf of the signer the logic of the inheriting contract should encode rules which respect the information within `commit`the authorizer includes `commit` in their signature to ensure the authorized contract will only execute intended actions(s). the Invoker logic MUST implement constraints on the contract execution based on information in the `commit`; otherwise, any EOA that signs an AUTH for the Invoker will be compromisedper EIP-3074, digest = keccak256(MAGIC || paddedChainId || paddedNonce || paddedInvokerAddress || commit)","params":{"commit":"- any 32-byte value used to commit to transaction validity conditions","nonce":"- signer's current nonce"},"returns":{"digest":"- sign the `digest` to authorize the invoker to execute the `calls`"}}},"version":1},"userdoc":{"kind":"user","methods":{"getDigest(bytes32,uint256)":{"notice":"produce a digest for the authorizer to sign"}},"version":1}},"settings":{"remappings":["forge-std/=lib/forge-std/src/"],"optimizer":{"enabled":true,"runs":200},"metadata":{"bytecodeHash":"ipfs"},"compilationTarget":{"src/BaseAuth.sol":"BaseAuth"},"libraries":{}},"sources":{"src/BaseAuth.sol":{"keccak256":"0x84e21d35b1a745c5d4798479ed22c16e8ae2f319de7c8f53c4eaa2fdca2b9dc7","urls":["bzz-raw://b89432fc50ffdd3d4a758d26a32ad744639159d8bd62338cea5ec5db1c9f3822","dweb:/ipfs/QmaDY8DaGBVXApria5vt7biaPWrLMMDJTirenLfHifcyTV"],"license":"UNLICENSED"}},"version":1},"ast":{"absolutePath":"src/BaseAuth.sol","id":105,"exportedSymbols":{"BaseAuth":[104]},"nodeType":"SourceUnit","src":"39:2401:0","nodes":[{"id":1,"nodeType":"PragmaDirective","src":"39:24:0","nodes":[],"literals":["solidity","^","0.8",".23"]},{"id":104,"nodeType":"ContractDefinition","src":"149:2290:0","nodes":[{"id":6,"nodeType":"VariableDeclaration","src":"253:27:0","nodes":[],"constant":true,"documentation":{"id":3,"nodeType":"StructuredDocumentation","src":"182:66:0","text":"@notice magic byte to disambiguate EIP-3074 signature payloads"},"mutability":"constant","name":"MAGIC","nameLocation":"268:5:0","scope":104,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint8","typeString":"uint8"},"typeName":{"id":4,"name":"uint8","nodeType":"ElementaryTypeName","src":"253:5:0","typeDescriptions":{"typeIdentifier":"t_uint8","typeString":"uint8"}},"value":{"hexValue":"30783034","id":5,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"276:4:0","typeDescriptions":{"typeIdentifier":"t_rational_4_by_1","typeString":"int_const 4"},"value":"0x04"},"visibility":"internal"},{"id":49,"nodeType":"FunctionDefinition","src":"1252:249:0","nodes":[],"body":{"id":48,"nodeType":"Block","src":"1339:162:0","nodes":[],"statements":[{"expression":{"id":46,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftHandSide":{"id":16,"name":"digest","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":14,"src":"1349:6:0","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}},"nodeType":"Assignment","operator":"=","rightHandSide":{"arguments":[{"arguments":[{"id":20,"name":"MAGIC","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":6,"src":"1397:5:0","typeDescriptions":{"typeIdentifier":"t_uint8","typeString":"uint8"}},{"arguments":[{"expression":{"id":23,"name":"block","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-4,"src":"1412:5:0","typeDescriptions":{"typeIdentifier":"t_magic_block","typeString":"block"}},"id":24,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberLocation":"1418:7:0","memberName":"chainid","nodeType":"MemberAccess","src":"1412:13:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":22,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"1404:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_bytes32_$","typeString":"type(bytes32)"},"typeName":{"id":21,"name":"bytes32","nodeType":"ElementaryTypeName","src":"1404:7:0","typeDescriptions":{}}},"id":25,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"nameLocations":[],"names":[],"nodeType":"FunctionCall","src":"1404:22:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}},{"arguments":[{"id":28,"name":"nonce","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":11,"src":"1436:5:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":27,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"1428:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_bytes32_$","typeString":"type(bytes32)"},"typeName":{"id":26,"name":"bytes32","nodeType":"ElementaryTypeName","src":"1428:7:0","typeDescriptions":{}}},"id":29,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"nameLocations":[],"names":[],"nodeType":"FunctionCall","src":"1428:14:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}},{"arguments":[{"arguments":[{"arguments":[{"arguments":[{"id":38,"name":"this","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-28,"src":"1476:4:0","typeDescriptions":{"typeIdentifier":"t_contract$_BaseAuth_$104","typeString":"contract BaseAuth"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_contract$_BaseAuth_$104","typeString":"contract BaseAuth"}],"id":37,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"1468:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_address_$","typeString":"type(address)"},"typeName":{"id":36,"name":"address","nodeType":"ElementaryTypeName","src":"1468:7:0","typeDescriptions":{}}},"id":39,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"nameLocations":[],"names":[],"nodeType":"FunctionCall","src":"1468:13:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"}],"id":35,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"1460:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint160_$","typeString":"type(uint160)"},"typeName":{"id":34,"name":"uint160","nodeType":"ElementaryTypeName","src":"1460:7:0","typeDescriptions":{}}},"id":40,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"nameLocations":[],"names":[],"nodeType":"FunctionCall","src":"1460:22:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint160","typeString":"uint160"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint160","typeString":"uint160"}],"id":33,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"1452:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_uint256_$","typeString":"type(uint256)"},"typeName":{"id":32,"name":"uint256","nodeType":"ElementaryTypeName","src":"1452:7:0","typeDescriptions":{}}},"id":41,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"nameLocations":[],"names":[],"nodeType":"FunctionCall","src":"1452:31:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint256","typeString":"uint256"}],"id":31,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"nodeType":"ElementaryTypeNameExpression","src":"1444:7:0","typeDescriptions":{"typeIdentifier":"t_type$_t_bytes32_$","typeString":"type(bytes32)"},"typeName":{"id":30,"name":"bytes32","nodeType":"ElementaryTypeName","src":"1444:7:0","typeDescriptions":{}}},"id":42,"isConstant":false,"isLValue":false,"isPure":false,"kind":"typeConversion","lValueRequested":false,"nameLocations":[],"names":[],"nodeType":"FunctionCall","src":"1444:40:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}},{"id":43,"name":"commit","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":9,"src":"1486:6:0","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint8","typeString":"uint8"},{"typeIdentifier":"t_bytes32","typeString":"bytes32"},{"typeIdentifier":"t_bytes32","typeString":"bytes32"},{"typeIdentifier":"t_bytes32","typeString":"bytes32"},{"typeIdentifier":"t_bytes32","typeString":"bytes32"}],"expression":{"id":18,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"1380:3:0","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":19,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberLocation":"1384:12:0","memberName":"encodePacked","nodeType":"MemberAccess","src":"1380:16:0","typeDescriptions":{"typeIdentifier":"t_function_abiencodepacked_pure$__$returns$_t_bytes_memory_ptr_$","typeString":"function () pure returns (bytes memory)"}},"id":44,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"nameLocations":[],"names":[],"nodeType":"FunctionCall","src":"1380:113:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":17,"name":"keccak256","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-8,"src":"1370:9:0","typeDescriptions":{"typeIdentifier":"t_function_keccak256_pure$_t_bytes_memory_ptr_$returns$_t_bytes32_$","typeString":"function (bytes memory) pure returns (bytes32)"}},"id":45,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"nameLocations":[],"names":[],"nodeType":"FunctionCall","src":"1370:124:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}},"src":"1349:145:0","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}},"id":47,"nodeType":"ExpressionStatement","src":"1349:145:0"}]},"documentation":{"id":7,"nodeType":"StructuredDocumentation","src":"287:960:0","text":"@notice produce a digest for the authorizer to sign\n @param commit - any 32-byte value used to commit to transaction validity conditions\n @param nonce - signer's current nonce\n @return digest - sign the `digest` to authorize the invoker to execute the `calls`\n @dev signing `digest` authorizes this contact to execute code on behalf of the signer\n the logic of the inheriting contract should encode rules which respect the information within `commit`\n @dev the authorizer includes `commit` in their signature to ensure the authorized contract will only execute intended actions(s).\n the Invoker logic MUST implement constraints on the contract execution based on information in the `commit`;\n otherwise, any EOA that signs an AUTH for the Invoker will be compromised\n @dev per EIP-3074, digest = keccak256(MAGIC || paddedChainId || paddedNonce || paddedInvokerAddress || commit)"},"functionSelector":"5bc928a7","implemented":true,"kind":"function","modifiers":[],"name":"getDigest","nameLocation":"1261:9:0","parameters":{"id":12,"nodeType":"ParameterList","parameters":[{"constant":false,"id":9,"mutability":"mutable","name":"commit","nameLocation":"1279:6:0","nodeType":"VariableDeclaration","scope":49,"src":"1271:14:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"},"typeName":{"id":8,"name":"bytes32","nodeType":"ElementaryTypeName","src":"1271:7:0","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}},"visibility":"internal"},{"constant":false,"id":11,"mutability":"mutable","name":"nonce","nameLocation":"1295:5:0","nodeType":"VariableDeclaration","scope":49,"src":"1287:13:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":10,"name":"uint256","nodeType":"ElementaryTypeName","src":"1287:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"1270:31:0"},"returnParameters":{"id":15,"nodeType":"ParameterList","parameters":[{"constant":false,"id":14,"mutability":"mutable","name":"digest","nameLocation":"1331:6:0","nodeType":"VariableDeclaration","scope":49,"src":"1323:14:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"},"typeName":{"id":13,"name":"bytes32","nodeType":"ElementaryTypeName","src":"1323:7:0","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}},"visibility":"internal"}],"src":"1322:16:0"},"scope":104,"stateMutability":"view","virtual":false,"visibility":"public"},{"id":78,"nodeType":"FunctionDefinition","src":"1507:340:0","nodes":[],"body":{"id":77,"nodeType":"Block","src":"1658:189:0","nodes":[],"statements":[{"assignments":[65],"declarations":[{"constant":false,"id":65,"mutability":"mutable","name":"authArgs","nameLocation":"1681:8:0","nodeType":"VariableDeclaration","scope":77,"src":"1668:21:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":64,"name":"bytes","nodeType":"ElementaryTypeName","src":"1668:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"}],"id":75,"initialValue":{"arguments":[{"arguments":[{"id":69,"name":"v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":55,"src":"1717:1:0","typeDescriptions":{"typeIdentifier":"t_uint8","typeString":"uint8"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint8","typeString":"uint8"}],"id":68,"name":"yParity","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":103,"src":"1709:7:0","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_uint8_$returns$_t_uint8_$","typeString":"function (uint8) pure returns (uint8)"}},"id":70,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"nameLocations":[],"names":[],"nodeType":"FunctionCall","src":"1709:10:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_uint8","typeString":"uint8"}},{"id":71,"name":"r","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":57,"src":"1721:1:0","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}},{"id":72,"name":"s","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":59,"src":"1724:1:0","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}},{"id":73,"name":"commit","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":53,"src":"1727:6:0","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_uint8","typeString":"uint8"},{"typeIdentifier":"t_bytes32","typeString":"bytes32"},{"typeIdentifier":"t_bytes32","typeString":"bytes32"},{"typeIdentifier":"t_bytes32","typeString":"bytes32"}],"expression":{"id":66,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"1692:3:0","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":67,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberLocation":"1696:12:0","memberName":"encodePacked","nodeType":"MemberAccess","src":"1692:16:0","typeDescriptions":{"typeIdentifier":"t_function_abiencodepacked_pure$__$returns$_t_bytes_memory_ptr_$","typeString":"function () pure returns (bytes memory)"}},"id":74,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"nameLocations":[],"names":[],"nodeType":"FunctionCall","src":"1692:42:0","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}},"nodeType":"VariableDeclarationStatement","src":"1668:66:0"},{"AST":{"nativeSrc":"1753:88:0","nodeType":"YulBlock","src":"1753:88:0","statements":[{"nativeSrc":"1767:64:0","nodeType":"YulAssignment","src":"1767:64:0","value":{"arguments":[{"name":"authority","nativeSrc":"1783:9:0","nodeType":"YulIdentifier","src":"1783:9:0"},{"arguments":[{"name":"authArgs","nativeSrc":"1798:8:0","nodeType":"YulIdentifier","src":"1798:8:0"},{"kind":"number","nativeSrc":"1808:4:0","nodeType":"YulLiteral","src":"1808:4:0","type":"","value":"0x20"}],"functionName":{"name":"add","nativeSrc":"1794:3:0","nodeType":"YulIdentifier","src":"1794:3:0"},"nativeSrc":"1794:19:0","nodeType":"YulFunctionCall","src":"1794:19:0"},{"arguments":[{"name":"authArgs","nativeSrc":"1821:8:0","nodeType":"YulIdentifier","src":"1821:8:0"}],"functionName":{"name":"mload","nativeSrc":"1815:5:0","nodeType":"YulIdentifier","src":"1815:5:0"},"nativeSrc":"1815:15:0","nodeType":"YulFunctionCall","src":"1815:15:0"}],"functionName":{"name":"auth","nativeSrc":"1778:4:0","nodeType":"YulIdentifier","src":"1778:4:0"},"nativeSrc":"1778:53:0","nodeType":"YulFunctionCall","src":"1778:53:0"},"variableNames":[{"name":"success","nativeSrc":"1767:7:0","nodeType":"YulIdentifier","src":"1767:7:0"}]}]},"evmVersion":"paris","externalReferences":[{"declaration":65,"isOffset":false,"isSlot":false,"src":"1798:8:0","valueSize":1},{"declaration":65,"isOffset":false,"isSlot":false,"src":"1821:8:0","valueSize":1},{"declaration":51,"isOffset":false,"isSlot":false,"src":"1783:9:0","valueSize":1},{"declaration":62,"isOffset":false,"isSlot":false,"src":"1767:7:0","valueSize":1}],"id":76,"nodeType":"InlineAssembly","src":"1744:97:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"authSimple","nameLocation":"1516:10:0","parameters":{"id":60,"nodeType":"ParameterList","parameters":[{"constant":false,"id":51,"mutability":"mutable","name":"authority","nameLocation":"1535:9:0","nodeType":"VariableDeclaration","scope":78,"src":"1527:17:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":50,"name":"address","nodeType":"ElementaryTypeName","src":"1527:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"},{"constant":false,"id":53,"mutability":"mutable","name":"commit","nameLocation":"1554:6:0","nodeType":"VariableDeclaration","scope":78,"src":"1546:14:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"},"typeName":{"id":52,"name":"bytes32","nodeType":"ElementaryTypeName","src":"1546:7:0","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}},"visibility":"internal"},{"constant":false,"id":55,"mutability":"mutable","name":"v","nameLocation":"1568:1:0","nodeType":"VariableDeclaration","scope":78,"src":"1562:7:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint8","typeString":"uint8"},"typeName":{"id":54,"name":"uint8","nodeType":"ElementaryTypeName","src":"1562:5:0","typeDescriptions":{"typeIdentifier":"t_uint8","typeString":"uint8"}},"visibility":"internal"},{"constant":false,"id":57,"mutability":"mutable","name":"r","nameLocation":"1579:1:0","nodeType":"VariableDeclaration","scope":78,"src":"1571:9:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"},"typeName":{"id":56,"name":"bytes32","nodeType":"ElementaryTypeName","src":"1571:7:0","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}},"visibility":"internal"},{"constant":false,"id":59,"mutability":"mutable","name":"s","nameLocation":"1590:1:0","nodeType":"VariableDeclaration","scope":78,"src":"1582:9:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"},"typeName":{"id":58,"name":"bytes32","nodeType":"ElementaryTypeName","src":"1582:7:0","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}},"visibility":"internal"}],"src":"1526:66:0"},"returnParameters":{"id":63,"nodeType":"ParameterList","parameters":[{"constant":false,"id":62,"mutability":"mutable","name":"success","nameLocation":"1645:7:0","nodeType":"VariableDeclaration","scope":78,"src":"1640:12:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"typeName":{"id":61,"name":"bool","nodeType":"ElementaryTypeName","src":"1640:4:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"visibility":"internal"}],"src":"1639:14:0"},"scope":104,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":93,"nodeType":"FunctionDefinition","src":"1853:278:0","nodes":[],"body":{"id":92,"nodeType":"Block","src":"2006:125:0","nodes":[],"statements":[{"AST":{"nativeSrc":"2025:100:0","nodeType":"YulBlock","src":"2025:100:0","statements":[{"nativeSrc":"2039:76:0","nodeType":"YulAssignment","src":"2039:76:0","value":{"arguments":[{"name":"gasLimit","nativeSrc":"2059:8:0","nodeType":"YulIdentifier","src":"2059:8:0"},{"name":"to","nativeSrc":"2069:2:0","nodeType":"YulIdentifier","src":"2069:2:0"},{"name":"value","nativeSrc":"2073:5:0","nodeType":"YulIdentifier","src":"2073:5:0"},{"arguments":[{"name":"data","nativeSrc":"2084:4:0","nodeType":"YulIdentifier","src":"2084:4:0"},{"kind":"number","nativeSrc":"2090:4:0","nodeType":"YulLiteral","src":"2090:4:0","type":"","value":"0x20"}],"functionName":{"name":"add","nativeSrc":"2080:3:0","nodeType":"YulIdentifier","src":"2080:3:0"},"nativeSrc":"2080:15:0","nodeType":"YulFunctionCall","src":"2080:15:0"},{"arguments":[{"name":"data","nativeSrc":"2103:4:0","nodeType":"YulIdentifier","src":"2103:4:0"}],"functionName":{"name":"mload","nativeSrc":"2097:5:0","nodeType":"YulIdentifier","src":"2097:5:0"},"nativeSrc":"2097:11:0","nodeType":"YulFunctionCall","src":"2097:11:0"},{"kind":"number","nativeSrc":"2110:1:0","nodeType":"YulLiteral","src":"2110:1:0","type":"","value":"0"},{"kind":"number","nativeSrc":"2113:1:0","nodeType":"YulLiteral","src":"2113:1:0","type":"","value":"0"}],"functionName":{"name":"authcall","nativeSrc":"2050:8:0","nodeType":"YulIdentifier","src":"2050:8:0"},"nativeSrc":"2050:65:0","nodeType":"YulFunctionCall","src":"2050:65:0"},"variableNames":[{"name":"success","nativeSrc":"2039:7:0","nodeType":"YulIdentifier","src":"2039:7:0"}]}]},"evmVersion":"paris","externalReferences":[{"declaration":82,"isOffset":false,"isSlot":false,"src":"2084:4:0","valueSize":1},{"declaration":82,"isOffset":false,"isSlot":false,"src":"2103:4:0","valueSize":1},{"declaration":86,"isOffset":false,"isSlot":false,"src":"2059:8:0","valueSize":1},{"declaration":89,"isOffset":false,"isSlot":false,"src":"2039:7:0","valueSize":1},{"declaration":80,"isOffset":false,"isSlot":false,"src":"2069:2:0","valueSize":1},{"declaration":84,"isOffset":false,"isSlot":false,"src":"2073:5:0","valueSize":1}],"id":91,"nodeType":"InlineAssembly","src":"2016:109:0"}]},"implemented":true,"kind":"function","modifiers":[],"name":"authCallSimple","nameLocation":"1862:14:0","parameters":{"id":87,"nodeType":"ParameterList","parameters":[{"constant":false,"id":80,"mutability":"mutable","name":"to","nameLocation":"1885:2:0","nodeType":"VariableDeclaration","scope":93,"src":"1877:10:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":79,"name":"address","nodeType":"ElementaryTypeName","src":"1877:7:0","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"},{"constant":false,"id":82,"mutability":"mutable","name":"data","nameLocation":"1902:4:0","nodeType":"VariableDeclaration","scope":93,"src":"1889:17:0","stateVariable":false,"storageLocation":"memory","typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes"},"typeName":{"id":81,"name":"bytes","nodeType":"ElementaryTypeName","src":"1889:5:0","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"},{"constant":false,"id":84,"mutability":"mutable","name":"value","nameLocation":"1916:5:0","nodeType":"VariableDeclaration","scope":93,"src":"1908:13:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":83,"name":"uint256","nodeType":"ElementaryTypeName","src":"1908:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"},{"constant":false,"id":86,"mutability":"mutable","name":"gasLimit","nameLocation":"1931:8:0","nodeType":"VariableDeclaration","scope":93,"src":"1923:16:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":85,"name":"uint256","nodeType":"ElementaryTypeName","src":"1923:7:0","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"1876:64:0"},"returnParameters":{"id":90,"nodeType":"ParameterList","parameters":[{"constant":false,"id":89,"mutability":"mutable","name":"success","nameLocation":"1993:7:0","nodeType":"VariableDeclaration","scope":93,"src":"1988:12:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"typeName":{"id":88,"name":"bool","nodeType":"ElementaryTypeName","src":"1988:4:0","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"visibility":"internal"}],"src":"1987:14:0"},"scope":104,"stateMutability":"pure","virtual":false,"visibility":"internal"},{"id":103,"nodeType":"FunctionDefinition","src":"2205:232:0","nodes":[],"body":{"id":102,"nodeType":"Block","src":"2269:168:0","nodes":[],"statements":[{"AST":{"nativeSrc":"2288:143:0","nodeType":"YulBlock","src":"2288:143:0","statements":[{"cases":[{"body":{"nativeSrc":"2341:25:0","nodeType":"YulBlock","src":"2341:25:0","statements":[{"nativeSrc":"2343:21:0","nodeType":"YulAssignment","src":"2343:21:0","value":{"arguments":[{"name":"v","nativeSrc":"2358:1:0","nodeType":"YulIdentifier","src":"2358:1:0"},{"kind":"number","nativeSrc":"2361:2:0","nodeType":"YulLiteral","src":"2361:2:0","type":"","value":"28"}],"functionName":{"name":"eq","nativeSrc":"2355:2:0","nodeType":"YulIdentifier","src":"2355:2:0"},"nativeSrc":"2355:9:0","nodeType":"YulFunctionCall","src":"2355:9:0"},"variableNames":[{"name":"yParity_","nativeSrc":"2343:8:0","nodeType":"YulIdentifier","src":"2343:8:0"}]}]},"nativeSrc":"2331:35:0","nodeType":"YulCase","src":"2331:35:0","value":{"kind":"bool","nativeSrc":"2336:4:0","nodeType":"YulLiteral","src":"2336:4:0","type":"","value":"true"}},{"body":{"nativeSrc":"2387:34:0","nodeType":"YulBlock","src":"2387:34:0","statements":[{"nativeSrc":"2389:30:0","nodeType":"YulAssignment","src":"2389:30:0","value":{"arguments":[{"arguments":[{"name":"v","nativeSrc":"2409:1:0","nodeType":"YulIdentifier","src":"2409:1:0"},{"kind":"number","nativeSrc":"2412:2:0","nodeType":"YulLiteral","src":"2412:2:0","type":"","value":"35"}],"functionName":{"name":"sub","nativeSrc":"2405:3:0","nodeType":"YulIdentifier","src":"2405:3:0"},"nativeSrc":"2405:10:0","nodeType":"YulFunctionCall","src":"2405:10:0"},{"kind":"number","nativeSrc":"2417:1:0","nodeType":"YulLiteral","src":"2417:1:0","type":"","value":"2"}],"functionName":{"name":"mod","nativeSrc":"2401:3:0","nodeType":"YulIdentifier","src":"2401:3:0"},"nativeSrc":"2401:18:0","nodeType":"YulFunctionCall","src":"2401:18:0"},"variableNames":[{"name":"yParity_","nativeSrc":"2389:8:0","nodeType":"YulIdentifier","src":"2389:8:0"}]}]},"nativeSrc":"2379:42:0","nodeType":"YulCase","src":"2379:42:0","value":"default"}],"expression":{"arguments":[{"name":"v","nativeSrc":"2312:1:0","nodeType":"YulIdentifier","src":"2312:1:0"},{"kind":"number","nativeSrc":"2315:2:0","nodeType":"YulLiteral","src":"2315:2:0","type":"","value":"35"}],"functionName":{"name":"lt","nativeSrc":"2309:2:0","nodeType":"YulIdentifier","src":"2309:2:0"},"nativeSrc":"2309:9:0","nodeType":"YulFunctionCall","src":"2309:9:0"},"nativeSrc":"2302:119:0","nodeType":"YulSwitch","src":"2302:119:0"}]},"evmVersion":"paris","externalReferences":[{"declaration":96,"isOffset":false,"isSlot":false,"src":"2312:1:0","valueSize":1},{"declaration":96,"isOffset":false,"isSlot":false,"src":"2358:1:0","valueSize":1},{"declaration":96,"isOffset":false,"isSlot":false,"src":"2409:1:0","valueSize":1},{"declaration":99,"isOffset":false,"isSlot":false,"src":"2343:8:0","valueSize":1},{"declaration":99,"isOffset":false,"isSlot":false,"src":"2389:8:0","valueSize":1}],"id":101,"nodeType":"InlineAssembly","src":"2279:152:0"}]},"documentation":{"id":94,"nodeType":"StructuredDocumentation","src":"2137:63:0","text":"@dev Internal helper to convert `v` to `yParity` for `AUTH`"},"implemented":true,"kind":"function","modifiers":[],"name":"yParity","nameLocation":"2214:7:0","parameters":{"id":97,"nodeType":"ParameterList","parameters":[{"constant":false,"id":96,"mutability":"mutable","name":"v","nameLocation":"2228:1:0","nodeType":"VariableDeclaration","scope":103,"src":"2222:7:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint8","typeString":"uint8"},"typeName":{"id":95,"name":"uint8","nodeType":"ElementaryTypeName","src":"2222:5:0","typeDescriptions":{"typeIdentifier":"t_uint8","typeString":"uint8"}},"visibility":"internal"}],"src":"2221:9:0"},"returnParameters":{"id":100,"nodeType":"ParameterList","parameters":[{"constant":false,"id":99,"mutability":"mutable","name":"yParity_","nameLocation":"2259:8:0","nodeType":"VariableDeclaration","scope":103,"src":"2253:14:0","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint8","typeString":"uint8"},"typeName":{"id":98,"name":"uint8","nodeType":"ElementaryTypeName","src":"2253:5:0","typeDescriptions":{"typeIdentifier":"t_uint8","typeString":"uint8"}},"visibility":"internal"}],"src":"2252:16:0"},"scope":104,"stateMutability":"pure","virtual":false,"visibility":"private"}],"abstract":true,"baseContracts":[],"canonicalName":"BaseAuth","contractDependencies":[],"contractKind":"contract","documentation":{"id":2,"nodeType":"StructuredDocumentation","src":"65:84:0","text":"@title BaseAuth\n @author Anna Carroll "},"fullyImplemented":true,"linearizedBaseContracts":[104],"name":"BaseAuth","nameLocation":"167:8:0","scope":105,"usedErrors":[],"usedEvents":[]}],"license":"UNLICENSED"},"id":0} -------------------------------------------------------------------------------- /crates/testing/resources/eip3074/out/GasSponsorInvoker.sol/GasSponsorInvoker.json: -------------------------------------------------------------------------------- 1 | {"abi":[{"type":"function","name":"getDigest","inputs":[{"name":"commit","type":"bytes32","internalType":"bytes32"},{"name":"nonce","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"digest","type":"bytes32","internalType":"bytes32"}],"stateMutability":"view"},{"type":"function","name":"sponsorCall","inputs":[{"name":"authority","type":"address","internalType":"address"},{"name":"v","type":"uint8","internalType":"uint8"},{"name":"r","type":"bytes32","internalType":"bytes32"},{"name":"s","type":"bytes32","internalType":"bytes32"},{"name":"to","type":"address","internalType":"address"},{"name":"data","type":"bytes","internalType":"bytes"},{"name":"value","type":"uint256","internalType":"uint256"}],"outputs":[{"name":"success","type":"bool","internalType":"bool"}],"stateMutability":"pure"}],"bytecode":{"object":"0x608060405234801561001057600080fd5b50610428806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c80635bc928a71461003b5780637fb86262146100a7575b600080fd5b610094610049366004610286565b604051600160fa1b6020820152466021820152604181018290523060618201526081810183905260009060a10160405160208183030381529060405280519060200120905092915050565b6040519081526020015b60405180910390f35b6100ba6100b53660046102c4565b6100ca565b604051901515815260200161009e565b6000808585856040516020016100e29392919061038d565b6040516020818303038152906040528051906020012090506101078a828b8b8b6101e5565b61014f5760405162461bcd60e51b8152602060048201526014602482015273105d5d1a1bdc9a5e985d1a5bdb8819985a5b195960621b60448201526064015b60405180910390fd5b6101918686868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092018290525089935091506102459050565b9150816101d85760405162461bcd60e51b815260206004820152601560248201527410d85b1b08195e1958dd5d1a5bdb8819985a5b1959605a1b6044820152606401610146565b5098975050505050505050565b6000806101f18561025d565b60405160f89190911b6001600160f81b0319166020820152602181018590526041810184905260618101879052608101604051602081830303815290604052905080516020820188f6979650505050505050565b6000806000855160208701868987f795945050505050565b6000602382106001811461027957600260238403069150610280565b601c831491505b50919050565b6000806040838503121561029957600080fd5b50508035926020909101359150565b80356001600160a01b03811681146102bf57600080fd5b919050565b60008060008060008060008060e0898b0312156102e057600080fd5b6102e9896102a8565b9750602089013560ff811681146102ff57600080fd5b9650604089013595506060890135945061031b60808a016102a8565b935060a089013567ffffffffffffffff8082111561033857600080fd5b818b0191508b601f83011261034c57600080fd5b81358181111561035b57600080fd5b8c602082850101111561036d57600080fd5b60208301955080945050505060c089013590509295985092959890939650565b6001600160a01b03841681526040602082018190528101829052818360608301376000818301606090810191909152601f909201601f191601019291505056fea26469706673582212207a1cdb5e67ba3699d31dc33aa64894d0bcca05c543fe1f0a348a37a0b0dad93164736f6c637827302e382e32342d646576656c6f702e323032342e352e332b636f6d6d69742e31383761313738610058","sourceMap":"221:1093:1:-:0;;;;;;;;;;;;;;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x608060405234801561001057600080fd5b50600436106100365760003560e01c80635bc928a71461003b5780637fb86262146100a7575b600080fd5b610094610049366004610286565b604051600160fa1b6020820152466021820152604181018290523060618201526081810183905260009060a10160405160208183030381529060405280519060200120905092915050565b6040519081526020015b60405180910390f35b6100ba6100b53660046102c4565b6100ca565b604051901515815260200161009e565b6000808585856040516020016100e29392919061038d565b6040516020818303038152906040528051906020012090506101078a828b8b8b6101e5565b61014f5760405162461bcd60e51b8152602060048201526014602482015273105d5d1a1bdc9a5e985d1a5bdb8819985a5b195960621b60448201526064015b60405180910390fd5b6101918686868080601f016020809104026020016040519081016040528093929190818152602001838380828437600092018290525089935091506102459050565b9150816101d85760405162461bcd60e51b815260206004820152601560248201527410d85b1b08195e1958dd5d1a5bdb8819985a5b1959605a1b6044820152606401610146565b5098975050505050505050565b6000806101f18561025d565b60405160f89190911b6001600160f81b0319166020820152602181018590526041810184905260618101879052608101604051602081830303815290604052905080516020820188f6979650505050505050565b6000806000855160208701868987f795945050505050565b6000602382106001811461027957600260238403069150610280565b601c831491505b50919050565b6000806040838503121561029957600080fd5b50508035926020909101359150565b80356001600160a01b03811681146102bf57600080fd5b919050565b60008060008060008060008060e0898b0312156102e057600080fd5b6102e9896102a8565b9750602089013560ff811681146102ff57600080fd5b9650604089013595506060890135945061031b60808a016102a8565b935060a089013567ffffffffffffffff8082111561033857600080fd5b818b0191508b601f83011261034c57600080fd5b81358181111561035b57600080fd5b8c602082850101111561036d57600080fd5b60208301955080945050505060c089013590509295985092959890939650565b6001600160a01b03841681526040602082018190528101829052818360608301376000818301606090810191909152601f909201601f191601019291505056fea26469706673582212207a1cdb5e67ba3699d31dc33aa64894d0bcca05c543fe1f0a348a37a0b0dad93164736f6c637827302e382e32342d646576656c6f702e323032342e352e332b636f6d6d69742e31383761313738610058","sourceMap":"221:1093:1:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1252:249:0;;;;;;:::i;:::-;1380:113;;-1:-1:-1;;;1380:113:0;;;2165:49:3;1412:13:0;2230:11:3;;;2223:27;2266:12;;;2259:28;;;1476:4:0;2303:12:3;;;2296:28;2340:12;;;2333:28;;;1323:14:0;;2377:13:3;;1380:113:0;;;;;;;;;;;;1370:124;;;;;;1349:145;;1252:249;;;;;;;;413:25:3;;;401:2;386:18;1252:249:0;;;;;;;;723:589:1;;;;;;:::i;:::-;;:::i;:::-;;;1901:14:3;;1894:22;1876:41;;1864:2;1849:18;723:589:1;1736:187:3;723:589:1;927:12;951:14;989:2;993:4;;978:20;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;968:31;;;;;;951:48;;1080:38;1091:9;1102:6;1110:1;1113;1116;1080:10;:38::i;:::-;1072:71;;;;-1:-1:-1;;;1072:71:1;;3093:2:3;1072:71:1;;;3075:21:3;3132:2;3112:18;;;3105:30;-1:-1:-1;;;3151:18:3;;;3144:50;3211:18;;1072:71:1;;;;;;;;;1220:34;1235:2;1239:4;;1220:34;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;1245:5:1;;-1:-1:-1;1220:34:1;-1:-1:-1;1220:14:1;;-1:-1:-1;1220:34:1:i;:::-;1210:44;;1272:7;1264:41;;;;-1:-1:-1;;;1264:41:1;;3442:2:3;1264:41:1;;;3424:21:3;3481:2;3461:18;;;3454:30;-1:-1:-1;;;3500:18:3;;;3493:51;3561:18;;1264:41:1;3240:345:3;1264:41:1;941:371;723:589;;;;;;;;;;:::o;1507:340:0:-;1640:12;1668:21;1709:10;1717:1;1709:7;:10::i;:::-;1692:42;;3837:3:3;3815:16;;;;-1:-1:-1;;;;;;3811:36:3;1692:42:0;;;3799:49:3;3864:11;;;3857:27;;;3900:12;;;3893:28;;;3937:12;;;3930:28;;;3974:12;;1692:42:0;;;;;;;;;;;;1668:66;;1821:8;1815:15;1808:4;1798:8;1794:19;1783:9;1778:53;1767:64;1507:340;-1:-1:-1;;;;;;;1507:340:0:o;1853:278::-;1988:12;2113:1;2110;2103:4;2097:11;2090:4;2084;2080:15;2073:5;2069:2;2059:8;2050:65;2039:76;1853:278;-1:-1:-1;;;;;1853:278:0:o;2205:232::-;2253:14;2315:2;2312:1;2309:9;2336:4;2331:35;;;;2417:1;2412:2;2409:1;2405:10;2401:18;2389:30;;2302:119;;2331:35;2361:2;2358:1;2355:9;2343:21;;2302:119;;2205:232;;;:::o;14:248:3:-;82:6;90;143:2;131:9;122:7;118:23;114:32;111:52;;;159:1;156;149:12;111:52;-1:-1:-1;;182:23:3;;;252:2;237:18;;;224:32;;-1:-1:-1;14:248:3:o;449:173::-;517:20;;-1:-1:-1;;;;;566:31:3;;556:42;;546:70;;612:1;609;602:12;546:70;449:173;;;:::o;627:1104::-;749:6;757;765;773;781;789;797;805;858:3;846:9;837:7;833:23;829:33;826:53;;;875:1;872;865:12;826:53;898:29;917:9;898:29;:::i;:::-;888:39;;977:2;966:9;962:18;949:32;1021:4;1014:5;1010:16;1003:5;1000:27;990:55;;1041:1;1038;1031:12;990:55;1064:5;-1:-1:-1;1116:2:3;1101:18;;1088:32;;-1:-1:-1;1167:2:3;1152:18;;1139:32;;-1:-1:-1;1190:39:3;1224:3;1209:19;;1190:39;:::i;:::-;1180:49;;1280:3;1269:9;1265:19;1252:33;1304:18;1345:2;1337:6;1334:14;1331:34;;;1361:1;1358;1351:12;1331:34;1399:6;1388:9;1384:22;1374:32;;1444:7;1437:4;1433:2;1429:13;1425:27;1415:55;;1466:1;1463;1456:12;1415:55;1506:2;1493:16;1532:2;1524:6;1521:14;1518:34;;;1548:1;1545;1538:12;1518:34;1593:7;1588:2;1579:6;1575:2;1571:15;1567:24;1564:37;1561:57;;;1614:1;1611;1604:12;1561:57;1645:2;1641;1637:11;1627:21;;1667:6;1657:16;;;;;1720:3;1709:9;1705:19;1692:33;1682:43;;627:1104;;;;;;;;;;;:::o;2401:485::-;-1:-1:-1;;;;;2586:32:3;;2568:51;;2655:2;2650;2635:18;;2628:30;;;2674:18;;2667:34;;;2694:6;2743;2738:2;2723:18;;2710:48;2807:1;2778:22;;;2802:2;2774:31;;;2767:42;;;;2870:2;2849:15;;;-1:-1:-1;;2845:29:3;2830:45;2826:54;;2401:485;-1:-1:-1;;2401:485:3:o","linkReferences":{}},"methodIdentifiers":{"getDigest(bytes32,uint256)":"5bc928a7","sponsorCall(address,uint8,bytes32,bytes32,address,bytes,uint256)":"7fb86262"},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.24-develop.2024.5.3+commit.187a178a\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"commit\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"nonce\",\"type\":\"uint256\"}],\"name\":\"getDigest\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"digest\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"authority\",\"type\":\"address\"},{\"internalType\":\"uint8\",\"name\":\"v\",\"type\":\"uint8\"},{\"internalType\":\"bytes32\",\"name\":\"r\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"s\",\"type\":\"bytes32\"},{\"internalType\":\"address\",\"name\":\"to\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"data\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"value\",\"type\":\"uint256\"}],\"name\":\"sponsorCall\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"success\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"getDigest(bytes32,uint256)\":{\"details\":\"signing `digest` authorizes this contact to execute code on behalf of the signer the logic of the inheriting contract should encode rules which respect the information within `commit`the authorizer includes `commit` in their signature to ensure the authorized contract will only execute intended actions(s). the Invoker logic MUST implement constraints on the contract execution based on information in the `commit`; otherwise, any EOA that signs an AUTH for the Invoker will be compromisedper EIP-3074, digest = keccak256(MAGIC || paddedChainId || paddedNonce || paddedInvokerAddress || commit)\",\"params\":{\"commit\":\"- any 32-byte value used to commit to transaction validity conditions\",\"nonce\":\"- signer's current nonce\"},\"returns\":{\"digest\":\"- sign the `digest` to authorize the invoker to execute the `calls`\"}},\"sponsorCall(address,uint8,bytes32,bytes32,address,bytes,uint256)\":{\"params\":{\"authority\":\"The address of the authorizing external account\",\"data\":\"The data payload for the call\",\"r\":\"Half of the ECDSA signature pair\",\"s\":\"Half of the ECDSA signature pair\",\"to\":\"The target contract address to call\",\"v\":\"The recovery byte of the signature\"},\"returns\":{\"success\":\"True if the call was successful\"}}},\"title\":\"Gas Sponsor Invoker\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{\"getDigest(bytes32,uint256)\":{\"notice\":\"produce a digest for the authorizer to sign\"},\"sponsorCall(address,uint8,bytes32,bytes32,address,bytes,uint256)\":{\"notice\":\"Executes a call authorized by an external account (EOA)\"}},\"notice\":\"Invoker contract using EIP-3074 to sponsor gas for authorized transactions\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/GasSponsorInvoker.sol\":\"GasSponsorInvoker\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[\":forge-std/=lib/forge-std/src/\"]},\"sources\":{\"src/BaseAuth.sol\":{\"keccak256\":\"0x84e21d35b1a745c5d4798479ed22c16e8ae2f319de7c8f53c4eaa2fdca2b9dc7\",\"license\":\"UNLICENSED\",\"urls\":[\"bzz-raw://b89432fc50ffdd3d4a758d26a32ad744639159d8bd62338cea5ec5db1c9f3822\",\"dweb:/ipfs/QmaDY8DaGBVXApria5vt7biaPWrLMMDJTirenLfHifcyTV\"]},\"src/GasSponsorInvoker.sol\":{\"keccak256\":\"0x8bba15a306e4b7cb11dd3463a201da374550a1000d3162ad92f7d2cd798d0a23\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://8013c4dbe1eb5dd89676df00d71b16c158d1296877c7cd3815131bb30a34d745\",\"dweb:/ipfs/QmNVxR8LawugLEZ3DwxMwhmKzUWTU8HjH4XpFio5QpNKZy\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.24-develop.2024.5.3+commit.187a178a"},"language":"Solidity","output":{"abi":[{"inputs":[{"internalType":"bytes32","name":"commit","type":"bytes32"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"stateMutability":"view","type":"function","name":"getDigest","outputs":[{"internalType":"bytes32","name":"digest","type":"bytes32"}]},{"inputs":[{"internalType":"address","name":"authority","type":"address"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"internalType":"address","name":"to","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"uint256","name":"value","type":"uint256"}],"stateMutability":"pure","type":"function","name":"sponsorCall","outputs":[{"internalType":"bool","name":"success","type":"bool"}]}],"devdoc":{"kind":"dev","methods":{"getDigest(bytes32,uint256)":{"details":"signing `digest` authorizes this contact to execute code on behalf of the signer the logic of the inheriting contract should encode rules which respect the information within `commit`the authorizer includes `commit` in their signature to ensure the authorized contract will only execute intended actions(s). the Invoker logic MUST implement constraints on the contract execution based on information in the `commit`; otherwise, any EOA that signs an AUTH for the Invoker will be compromisedper EIP-3074, digest = keccak256(MAGIC || paddedChainId || paddedNonce || paddedInvokerAddress || commit)","params":{"commit":"- any 32-byte value used to commit to transaction validity conditions","nonce":"- signer's current nonce"},"returns":{"digest":"- sign the `digest` to authorize the invoker to execute the `calls`"}},"sponsorCall(address,uint8,bytes32,bytes32,address,bytes,uint256)":{"params":{"authority":"The address of the authorizing external account","data":"The data payload for the call","r":"Half of the ECDSA signature pair","s":"Half of the ECDSA signature pair","to":"The target contract address to call","v":"The recovery byte of the signature"},"returns":{"success":"True if the call was successful"}}},"version":1},"userdoc":{"kind":"user","methods":{"getDigest(bytes32,uint256)":{"notice":"produce a digest for the authorizer to sign"},"sponsorCall(address,uint8,bytes32,bytes32,address,bytes,uint256)":{"notice":"Executes a call authorized by an external account (EOA)"}},"version":1}},"settings":{"remappings":["forge-std/=lib/forge-std/src/"],"optimizer":{"enabled":true,"runs":200},"metadata":{"bytecodeHash":"ipfs"},"compilationTarget":{"src/GasSponsorInvoker.sol":"GasSponsorInvoker"},"libraries":{}},"sources":{"src/BaseAuth.sol":{"keccak256":"0x84e21d35b1a745c5d4798479ed22c16e8ae2f319de7c8f53c4eaa2fdca2b9dc7","urls":["bzz-raw://b89432fc50ffdd3d4a758d26a32ad744639159d8bd62338cea5ec5db1c9f3822","dweb:/ipfs/QmaDY8DaGBVXApria5vt7biaPWrLMMDJTirenLfHifcyTV"],"license":"UNLICENSED"},"src/GasSponsorInvoker.sol":{"keccak256":"0x8bba15a306e4b7cb11dd3463a201da374550a1000d3162ad92f7d2cd798d0a23","urls":["bzz-raw://8013c4dbe1eb5dd89676df00d71b16c158d1296877c7cd3815131bb30a34d745","dweb:/ipfs/QmNVxR8LawugLEZ3DwxMwhmKzUWTU8HjH4XpFio5QpNKZy"],"license":"MIT"}},"version":1},"ast":{"absolutePath":"src/GasSponsorInvoker.sol","id":169,"exportedSymbols":{"BaseAuth":[104],"GasSponsorInvoker":[168]},"nodeType":"SourceUnit","src":"33:1282:1","nodes":[{"id":106,"nodeType":"PragmaDirective","src":"33:24:1","nodes":[],"literals":["solidity","^","0.8",".23"]},{"id":108,"nodeType":"ImportDirective","src":"59:42:1","nodes":[],"absolutePath":"src/BaseAuth.sol","file":"./BaseAuth.sol","nameLocation":"-1:-1:-1","scope":169,"sourceUnit":105,"symbolAliases":[{"foreign":{"id":107,"name":"BaseAuth","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":104,"src":"68:8:1","typeDescriptions":{}},"nameLocation":"-1:-1:-1"}],"unitAlias":""},{"id":168,"nodeType":"ContractDefinition","src":"221:1093:1","nodes":[{"id":167,"nodeType":"FunctionDefinition","src":"723:589:1","nodes":[],"body":{"id":166,"nodeType":"Block","src":"941:371:1","nodes":[],"statements":[{"assignments":[132],"declarations":[{"constant":false,"id":132,"mutability":"mutable","name":"commit","nameLocation":"959:6:1","nodeType":"VariableDeclaration","scope":166,"src":"951:14:1","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"},"typeName":{"id":131,"name":"bytes32","nodeType":"ElementaryTypeName","src":"951:7:1","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}},"visibility":"internal"}],"id":140,"initialValue":{"arguments":[{"arguments":[{"id":136,"name":"to","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":122,"src":"989:2:1","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},{"id":137,"name":"data","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":124,"src":"993:4:1","typeDescriptions":{"typeIdentifier":"t_bytes_calldata_ptr","typeString":"bytes calldata"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"},{"typeIdentifier":"t_bytes_calldata_ptr","typeString":"bytes calldata"}],"expression":{"id":134,"name":"abi","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-1,"src":"978:3:1","typeDescriptions":{"typeIdentifier":"t_magic_abi","typeString":"abi"}},"id":135,"isConstant":false,"isLValue":false,"isPure":true,"lValueRequested":false,"memberLocation":"982:6:1","memberName":"encode","nodeType":"MemberAccess","src":"978:10:1","typeDescriptions":{"typeIdentifier":"t_function_abiencode_pure$__$returns$_t_bytes_memory_ptr_$","typeString":"function () pure returns (bytes memory)"}},"id":138,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"nameLocations":[],"names":[],"nodeType":"FunctionCall","src":"978:20:1","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bytes_memory_ptr","typeString":"bytes memory"}],"id":133,"name":"keccak256","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-8,"src":"968:9:1","typeDescriptions":{"typeIdentifier":"t_function_keccak256_pure$_t_bytes_memory_ptr_$returns$_t_bytes32_$","typeString":"function (bytes memory) pure returns (bytes32)"}},"id":139,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"nameLocations":[],"names":[],"nodeType":"FunctionCall","src":"968:31:1","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}},"nodeType":"VariableDeclarationStatement","src":"951:48:1"},{"expression":{"arguments":[{"arguments":[{"id":143,"name":"authority","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":114,"src":"1091:9:1","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},{"id":144,"name":"commit","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":132,"src":"1102:6:1","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}},{"id":145,"name":"v","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":116,"src":"1110:1:1","typeDescriptions":{"typeIdentifier":"t_uint8","typeString":"uint8"}},{"id":146,"name":"r","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":118,"src":"1113:1:1","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}},{"id":147,"name":"s","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":120,"src":"1116:1:1","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"},{"typeIdentifier":"t_bytes32","typeString":"bytes32"},{"typeIdentifier":"t_uint8","typeString":"uint8"},{"typeIdentifier":"t_bytes32","typeString":"bytes32"},{"typeIdentifier":"t_bytes32","typeString":"bytes32"}],"id":142,"name":"authSimple","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":78,"src":"1080:10:1","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_address_$_t_bytes32_$_t_uint8_$_t_bytes32_$_t_bytes32_$returns$_t_bool_$","typeString":"function (address,bytes32,uint8,bytes32,bytes32) pure returns (bool)"}},"id":148,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"nameLocations":[],"names":[],"nodeType":"FunctionCall","src":"1080:38:1","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"hexValue":"417574686f72697a6174696f6e206661696c6564","id":149,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"1120:22:1","typeDescriptions":{"typeIdentifier":"t_stringliteral_d17879a98600e1a5c06e04b44ff2ef968028e429d859826d7a01e35fbf3c9eef","typeString":"literal_string \"Authorization failed\""},"value":"Authorization failed"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_stringliteral_d17879a98600e1a5c06e04b44ff2ef968028e429d859826d7a01e35fbf3c9eef","typeString":"literal_string \"Authorization failed\""}],"id":141,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"1072:7:1","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":150,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"nameLocations":[],"names":[],"nodeType":"FunctionCall","src":"1072:71:1","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":151,"nodeType":"ExpressionStatement","src":"1072:71:1"},{"expression":{"id":159,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftHandSide":{"id":152,"name":"success","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":129,"src":"1210:7:1","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"nodeType":"Assignment","operator":"=","rightHandSide":{"arguments":[{"id":154,"name":"to","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":122,"src":"1235:2:1","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},{"id":155,"name":"data","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":124,"src":"1239:4:1","typeDescriptions":{"typeIdentifier":"t_bytes_calldata_ptr","typeString":"bytes calldata"}},{"id":156,"name":"value","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":126,"src":"1245:5:1","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},{"hexValue":"30","id":157,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"1252:1:1","typeDescriptions":{"typeIdentifier":"t_rational_0_by_1","typeString":"int_const 0"},"value":"0"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_address","typeString":"address"},{"typeIdentifier":"t_bytes_calldata_ptr","typeString":"bytes calldata"},{"typeIdentifier":"t_uint256","typeString":"uint256"},{"typeIdentifier":"t_rational_0_by_1","typeString":"int_const 0"}],"id":153,"name":"authCallSimple","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":93,"src":"1220:14:1","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$_t_address_$_t_bytes_memory_ptr_$_t_uint256_$_t_uint256_$returns$_t_bool_$","typeString":"function (address,bytes memory,uint256,uint256) pure returns (bool)"}},"id":158,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"nameLocations":[],"names":[],"nodeType":"FunctionCall","src":"1220:34:1","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"src":"1210:44:1","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"id":160,"nodeType":"ExpressionStatement","src":"1210:44:1"},{"expression":{"arguments":[{"id":162,"name":"success","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":129,"src":"1272:7:1","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},{"hexValue":"43616c6c20657865637574696f6e206661696c6564","id":163,"isConstant":false,"isLValue":false,"isPure":true,"kind":"string","lValueRequested":false,"nodeType":"Literal","src":"1281:23:1","typeDescriptions":{"typeIdentifier":"t_stringliteral_2796c61c946df02007454e4fe25eeedbdb7345d33153a0e3ee502b088b313018","typeString":"literal_string \"Call execution failed\""},"value":"Call execution failed"}],"expression":{"argumentTypes":[{"typeIdentifier":"t_bool","typeString":"bool"},{"typeIdentifier":"t_stringliteral_2796c61c946df02007454e4fe25eeedbdb7345d33153a0e3ee502b088b313018","typeString":"literal_string \"Call execution failed\""}],"id":161,"name":"require","nodeType":"Identifier","overloadedDeclarations":[-18,-18],"referencedDeclaration":-18,"src":"1264:7:1","typeDescriptions":{"typeIdentifier":"t_function_require_pure$_t_bool_$_t_string_memory_ptr_$returns$__$","typeString":"function (bool,string memory) pure"}},"id":164,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"nameLocations":[],"names":[],"nodeType":"FunctionCall","src":"1264:41:1","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":165,"nodeType":"ExpressionStatement","src":"1264:41:1"}]},"documentation":{"id":112,"nodeType":"StructuredDocumentation","src":"266:452:1","text":"@notice Executes a call authorized by an external account (EOA)\n @param authority The address of the authorizing external account\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 @param to The target contract address to call\n @param data The data payload for the call\n @return success True if the call was successful"},"functionSelector":"7fb86262","implemented":true,"kind":"function","modifiers":[],"name":"sponsorCall","nameLocation":"732:11:1","parameters":{"id":127,"nodeType":"ParameterList","parameters":[{"constant":false,"id":114,"mutability":"mutable","name":"authority","nameLocation":"761:9:1","nodeType":"VariableDeclaration","scope":167,"src":"753:17:1","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":113,"name":"address","nodeType":"ElementaryTypeName","src":"753:7:1","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"},{"constant":false,"id":116,"mutability":"mutable","name":"v","nameLocation":"786:1:1","nodeType":"VariableDeclaration","scope":167,"src":"780:7:1","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint8","typeString":"uint8"},"typeName":{"id":115,"name":"uint8","nodeType":"ElementaryTypeName","src":"780:5:1","typeDescriptions":{"typeIdentifier":"t_uint8","typeString":"uint8"}},"visibility":"internal"},{"constant":false,"id":118,"mutability":"mutable","name":"r","nameLocation":"805:1:1","nodeType":"VariableDeclaration","scope":167,"src":"797:9:1","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"},"typeName":{"id":117,"name":"bytes32","nodeType":"ElementaryTypeName","src":"797:7:1","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}},"visibility":"internal"},{"constant":false,"id":120,"mutability":"mutable","name":"s","nameLocation":"824:1:1","nodeType":"VariableDeclaration","scope":167,"src":"816:9:1","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"},"typeName":{"id":119,"name":"bytes32","nodeType":"ElementaryTypeName","src":"816:7:1","typeDescriptions":{"typeIdentifier":"t_bytes32","typeString":"bytes32"}},"visibility":"internal"},{"constant":false,"id":122,"mutability":"mutable","name":"to","nameLocation":"843:2:1","nodeType":"VariableDeclaration","scope":167,"src":"835:10:1","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":121,"name":"address","nodeType":"ElementaryTypeName","src":"835:7:1","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"internal"},{"constant":false,"id":124,"mutability":"mutable","name":"data","nameLocation":"870:4:1","nodeType":"VariableDeclaration","scope":167,"src":"855:19:1","stateVariable":false,"storageLocation":"calldata","typeDescriptions":{"typeIdentifier":"t_bytes_calldata_ptr","typeString":"bytes"},"typeName":{"id":123,"name":"bytes","nodeType":"ElementaryTypeName","src":"855:5:1","typeDescriptions":{"typeIdentifier":"t_bytes_storage_ptr","typeString":"bytes"}},"visibility":"internal"},{"constant":false,"id":126,"mutability":"mutable","name":"value","nameLocation":"892:5:1","nodeType":"VariableDeclaration","scope":167,"src":"884:13:1","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":125,"name":"uint256","nodeType":"ElementaryTypeName","src":"884:7:1","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"743:160:1"},"returnParameters":{"id":130,"nodeType":"ParameterList","parameters":[{"constant":false,"id":129,"mutability":"mutable","name":"success","nameLocation":"932:7:1","nodeType":"VariableDeclaration","scope":167,"src":"927:12:1","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"typeName":{"id":128,"name":"bool","nodeType":"ElementaryTypeName","src":"927:4:1","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"}},"visibility":"internal"}],"src":"926:14:1"},"scope":168,"stateMutability":"pure","virtual":false,"visibility":"external"}],"abstract":false,"baseContracts":[{"baseName":{"id":110,"name":"BaseAuth","nameLocations":["251:8:1"],"nodeType":"IdentifierPath","referencedDeclaration":104,"src":"251:8:1"},"id":111,"nodeType":"InheritanceSpecifier","src":"251:8:1"}],"canonicalName":"GasSponsorInvoker","contractDependencies":[],"contractKind":"contract","documentation":{"id":109,"nodeType":"StructuredDocumentation","src":"103:118:1","text":"@title Gas Sponsor Invoker\n @notice Invoker contract using EIP-3074 to sponsor gas for authorized transactions"},"fullyImplemented":true,"linearizedBaseContracts":[168,104],"name":"GasSponsorInvoker","nameLocation":"230:17:1","scope":169,"usedErrors":[],"usedEvents":[]}],"license":"MIT"},"id":1} -------------------------------------------------------------------------------- /crates/testing/resources/eip3074/out/SenderRecorder.sol/SenderRecorder.json: -------------------------------------------------------------------------------- 1 | {"abi":[{"type":"function","name":"lastSender","inputs":[],"outputs":[{"name":"","type":"address","internalType":"address"}],"stateMutability":"view"},{"type":"function","name":"recordSender","inputs":[],"outputs":[],"stateMutability":"nonpayable"}],"bytecode":{"object":"0x608060405234801561001057600080fd5b5060d88061001f6000396000f3fe6080604052348015600f57600080fd5b506004361060325760003560e01c8063256fec88146037578063f1627ecf146065575b600080fd5b6000546049906001600160a01b031681565b6040516001600160a01b03909116815260200160405180910390f35b607b600080546001600160a01b03191633179055565b00fea264697066735822122049551feb180f5e5eadb2436dbceb4b72918c3ddab0adc2c72581d451a7d256cc64736f6c637827302e382e32342d646576656c6f702e323032342e352e332b636f6d6d69742e31383761313738610058","sourceMap":"59:137:2:-:0;;;;;;;;;;;;;;;;;;;","linkReferences":{}},"deployedBytecode":{"object":"0x6080604052348015600f57600080fd5b506004361060325760003560e01c8063256fec88146037578063f1627ecf146065575b600080fd5b6000546049906001600160a01b031681565b6040516001600160a01b03909116815260200160405180910390f35b607b600080546001600160a01b03191633179055565b00fea264697066735822122049551feb180f5e5eadb2436dbceb4b72918c3ddab0adc2c72581d451a7d256cc64736f6c637827302e382e32342d646576656c6f702e323032342e352e332b636f6d6d69742e31383761313738610058","sourceMap":"59:137:2:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;89:25;;;;;-1:-1:-1;;;;;89:25:2;;;;;;-1:-1:-1;;;;;178:32:3;;;160:51;;148:2;133:18;89:25:2;;;;;;;121:73;;164:10;:23;;-1:-1:-1;;;;;;164:23:2;177:10;164:23;;;121:73;;","linkReferences":{}},"methodIdentifiers":{"lastSender()":"256fec88","recordSender()":"f1627ecf"},"rawMetadata":"{\"compiler\":{\"version\":\"0.8.24-develop.2024.5.3+commit.187a178a\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[],\"name\":\"lastSender\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"recordSender\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"version\":1}},\"settings\":{\"compilationTarget\":{\"src/SenderRecorder.sol\":\"SenderRecorder\"},\"evmVersion\":\"paris\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\"},\"optimizer\":{\"enabled\":true,\"runs\":200},\"remappings\":[\":forge-std/=lib/forge-std/src/\"]},\"sources\":{\"src/SenderRecorder.sol\":{\"keccak256\":\"0xe3c1539c8d463d0da78faa757e8f9222a506ef1059cce528f25c6429f537e33e\",\"license\":\"MIT\",\"urls\":[\"bzz-raw://2f1ad600dc36b1be2b715dbd8fc1b3d13432c46abde93d8743cfe4830443cac4\",\"dweb:/ipfs/QmTriKHpTzaLZ2BSpjQTGZ1k93mcgJyiKbBiPxd674ckrR\"]}},\"version\":1}","metadata":{"compiler":{"version":"0.8.24-develop.2024.5.3+commit.187a178a"},"language":"Solidity","output":{"abi":[{"inputs":[],"stateMutability":"view","type":"function","name":"lastSender","outputs":[{"internalType":"address","name":"","type":"address"}]},{"inputs":[],"stateMutability":"nonpayable","type":"function","name":"recordSender"}],"devdoc":{"kind":"dev","methods":{},"version":1},"userdoc":{"kind":"user","methods":{},"version":1}},"settings":{"remappings":["forge-std/=lib/forge-std/src/"],"optimizer":{"enabled":true,"runs":200},"metadata":{"bytecodeHash":"ipfs"},"compilationTarget":{"src/SenderRecorder.sol":"SenderRecorder"},"libraries":{}},"sources":{"src/SenderRecorder.sol":{"keccak256":"0xe3c1539c8d463d0da78faa757e8f9222a506ef1059cce528f25c6429f537e33e","urls":["bzz-raw://2f1ad600dc36b1be2b715dbd8fc1b3d13432c46abde93d8743cfe4830443cac4","dweb:/ipfs/QmTriKHpTzaLZ2BSpjQTGZ1k93mcgJyiKbBiPxd674ckrR"],"license":"MIT"}},"version":1},"ast":{"absolutePath":"src/SenderRecorder.sol","id":183,"exportedSymbols":{"SenderRecorder":[182]},"nodeType":"SourceUnit","src":"33:164:2","nodes":[{"id":170,"nodeType":"PragmaDirective","src":"33:24:2","nodes":[],"literals":["solidity","^","0.8",".23"]},{"id":182,"nodeType":"ContractDefinition","src":"59:137:2","nodes":[{"id":172,"nodeType":"VariableDeclaration","src":"89:25:2","nodes":[],"constant":false,"functionSelector":"256fec88","mutability":"mutable","name":"lastSender","nameLocation":"104:10:2","scope":182,"stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"},"typeName":{"id":171,"name":"address","nodeType":"ElementaryTypeName","src":"89:7:2","stateMutability":"nonpayable","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"visibility":"public"},{"id":181,"nodeType":"FunctionDefinition","src":"121:73:2","nodes":[],"body":{"id":180,"nodeType":"Block","src":"154:40:2","nodes":[],"statements":[{"expression":{"id":178,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"leftHandSide":{"id":175,"name":"lastSender","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":172,"src":"164:10:2","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"nodeType":"Assignment","operator":"=","rightHandSide":{"expression":{"id":176,"name":"msg","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":-15,"src":"177:3:2","typeDescriptions":{"typeIdentifier":"t_magic_message","typeString":"msg"}},"id":177,"isConstant":false,"isLValue":false,"isPure":false,"lValueRequested":false,"memberLocation":"181:6:2","memberName":"sender","nodeType":"MemberAccess","src":"177:10:2","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"src":"164:23:2","typeDescriptions":{"typeIdentifier":"t_address","typeString":"address"}},"id":179,"nodeType":"ExpressionStatement","src":"164:23:2"}]},"functionSelector":"f1627ecf","implemented":true,"kind":"function","modifiers":[],"name":"recordSender","nameLocation":"130:12:2","parameters":{"id":173,"nodeType":"ParameterList","parameters":[],"src":"142:2:2"},"returnParameters":{"id":174,"nodeType":"ParameterList","parameters":[],"src":"154:0:2"},"scope":182,"stateMutability":"nonpayable","virtual":false,"visibility":"external"}],"abstract":false,"baseContracts":[],"canonicalName":"SenderRecorder","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"linearizedBaseContracts":[182],"name":"SenderRecorder","nameLocation":"68:14:2","scope":183,"usedErrors":[],"usedEvents":[]}],"license":"MIT"},"id":2} -------------------------------------------------------------------------------- /crates/testing/resources/eip3074/src/BaseAuth.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: UNLICENSED 2 | pragma solidity ^0.8.23; 3 | 4 | /// @title BaseAuth 5 | /// @author Anna Carroll 6 | abstract contract BaseAuth { 7 | /// @notice magic byte to disambiguate EIP-3074 signature payloads 8 | uint8 constant MAGIC = 0x04; 9 | 10 | /// @notice produce a digest for the authorizer to sign 11 | /// @param commit - any 32-byte value used to commit to transaction validity conditions 12 | /// @param nonce - signer's current nonce 13 | /// @return digest - sign the `digest` to authorize the invoker to execute the `calls` 14 | /// @dev signing `digest` authorizes this contact to execute code on behalf of the signer 15 | /// the logic of the inheriting contract should encode rules which respect the information within `commit` 16 | /// @dev the authorizer includes `commit` in their signature to ensure the authorized contract will only execute intended actions(s). 17 | /// the Invoker logic MUST implement constraints on the contract execution based on information in the `commit`; 18 | /// otherwise, any EOA that signs an AUTH for the Invoker will be compromised 19 | /// @dev per EIP-3074, digest = keccak256(MAGIC || paddedChainId || paddedNonce || paddedInvokerAddress || commit) 20 | function getDigest(bytes32 commit, uint256 nonce) public view returns (bytes32 digest) { 21 | digest = 22 | keccak256(abi.encodePacked(MAGIC, bytes32(block.chainid), bytes32(nonce), bytes32(uint256(uint160(address(this)))), commit)); 23 | } 24 | 25 | function authSimple(address authority, bytes32 commit, uint8 v, bytes32 r, bytes32 s) 26 | internal 27 | pure 28 | returns (bool success) 29 | { 30 | bytes memory authArgs = abi.encodePacked(yParity(v), r, s, commit); 31 | assembly { 32 | success := auth(authority, add(authArgs, 0x20), mload(authArgs)) 33 | } 34 | } 35 | 36 | function authCallSimple(address to, bytes memory data, uint256 value, uint256 gasLimit) 37 | internal 38 | pure 39 | returns (bool success) 40 | { 41 | assembly { 42 | success := authcall(gasLimit, to, value, add(data, 0x20), mload(data), 0, 0) 43 | } 44 | } 45 | 46 | /// @dev Internal helper to convert `v` to `yParity` for `AUTH` 47 | function yParity(uint8 v) private pure returns (uint8 yParity_) { 48 | assembly { 49 | switch lt(v, 35) 50 | case true { yParity_ := eq(v, 28) } 51 | default { yParity_ := mod(sub(v, 35), 2) } 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /crates/testing/resources/eip3074/src/GasSponsorInvoker.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.23; 4 | 5 | import { BaseAuth } from "./BaseAuth.sol"; 6 | 7 | /// @title Gas Sponsor Invoker 8 | /// @notice Invoker contract using EIP-3074 to sponsor gas for authorized transactions 9 | contract GasSponsorInvoker is BaseAuth { 10 | /// @notice Executes a call authorized by an external account (EOA) 11 | /// @param authority The address of the authorizing external account 12 | /// @param v The recovery byte of the signature 13 | /// @param r Half of the ECDSA signature pair 14 | /// @param s Half of the ECDSA signature pair 15 | /// @param to The target contract address to call 16 | /// @param data The data payload for the call 17 | /// @return success True if the call was successful 18 | function sponsorCall( 19 | address authority, 20 | uint8 v, 21 | bytes32 r, 22 | bytes32 s, 23 | address to, 24 | bytes calldata data, 25 | uint256 value 26 | ) external pure returns (bool success) { 27 | bytes32 commit = keccak256(abi.encode(to, data)); 28 | 29 | // Ensure the transaction is authorized by the signer 30 | require(authSimple(authority, commit, v, r, s), "Authorization failed"); 31 | 32 | // Execute the call as authorized by the signer 33 | success = authCallSimple(to, data, value, 0); 34 | require(success, "Call execution failed"); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /crates/testing/resources/eip3074/src/SenderRecorder.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.23; 4 | 5 | contract SenderRecorder { 6 | address public lastSender; 7 | 8 | function recordSender() external { 9 | lastSender = msg.sender; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /crates/testing/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Alphanet-testing module 2 | 3 | // todo(onbjerg): uncomment this when adding a test, 4 | // it was commented out due to removing our bls tests since they are now 5 | // in revm 6 | // #![warn(unused_crate_dependencies)] 7 | 8 | #[cfg(test)] 9 | mod tests; 10 | -------------------------------------------------------------------------------- /crates/testing/src/tests.rs: -------------------------------------------------------------------------------- 1 | #[test] 2 | fn dummy() { 3 | // kept here to prevent the ci from failing on no tests 4 | } 5 | -------------------------------------------------------------------------------- /crates/wallet/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "alphanet-wallet" 3 | version.workspace = true 4 | edition.workspace = true 5 | rust-version.workspace = true 6 | authors.workspace = true 7 | license.workspace = true 8 | repository.workspace = true 9 | keywords.workspace = true 10 | categories.workspace = true 11 | 12 | [dependencies] 13 | alloy-network.workspace = true 14 | alloy-primitives.workspace = true 15 | alloy-rpc-types.workspace = true 16 | 17 | reth-primitives.workspace = true 18 | reth-storage-api.workspace = true 19 | reth-rpc-eth-api.workspace = true 20 | reth-revm.workspace = true 21 | 22 | jsonrpsee = { workspace = true, features = ["server", "macros"] } 23 | serde = { workspace = true, features = ["derive"] } 24 | thiserror.workspace = true 25 | tracing.workspace = true 26 | tokio = { workspace = true, features = ["sync"] } 27 | 28 | [dev-dependencies] 29 | serde_json.workspace = true 30 | jsonrpsee = { workspace = true, features = ["server", "client", "macros"] } 31 | 32 | [lints] 33 | workspace = true 34 | -------------------------------------------------------------------------------- /crates/wallet/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! # AlphaNet wallet. 2 | //! 3 | //! Implementations of a custom `wallet_` namespace for AlphaNet experiment 1. 4 | //! 5 | //! - `wallet_getCapabilities` based on [EIP-5792][eip-5792], with the only capability being 6 | //! `delegation`. 7 | //! - `wallet_sendTransaction` that can perform sequencer-sponsored [EIP-7702][eip-7702] delegations 8 | //! and send other sequencer-sponsored transactions on behalf of EOAs with delegated code. 9 | //! 10 | //! # Restrictions 11 | //! 12 | //! `wallet_sendTransaction` has additional verifications in place to prevent some rudimentary abuse 13 | //! of the sequencer's funds. For example, transactions cannot contain any `value`. 14 | //! 15 | //! [eip-5792]: https://eips.ethereum.org/EIPS/eip-5792 16 | //! [eip-7702]: https://eips.ethereum.org/EIPS/eip-7702 17 | 18 | #![cfg_attr(not(test), warn(unused_crate_dependencies))] 19 | 20 | use alloy_network::{ 21 | eip2718::Encodable2718, Ethereum, EthereumWallet, NetworkWallet, TransactionBuilder, 22 | }; 23 | use alloy_primitives::{map::HashMap, Address, ChainId, TxHash, TxKind, U256}; 24 | use alloy_rpc_types::TransactionRequest; 25 | use jsonrpsee::{ 26 | core::{async_trait, RpcResult}, 27 | proc_macros::rpc, 28 | }; 29 | use reth_primitives::{revm_primitives::Bytecode, BlockId}; 30 | use reth_rpc_eth_api::helpers::{EthCall, EthState, EthTransactions, FullEthApi, LoadFee}; 31 | use reth_storage_api::{StateProvider, StateProviderFactory}; 32 | use serde::{Deserialize, Serialize}; 33 | use std::sync::Arc; 34 | use tracing::{trace, warn}; 35 | 36 | use reth_revm as _; 37 | use tokio::sync::Mutex; 38 | 39 | /// The capability to perform [EIP-7702][eip-7702] delegations, sponsored by the sequencer. 40 | /// 41 | /// The sequencer will only perform delegations, and act on behalf of delegated accounts, if the 42 | /// account delegates to one of the addresses specified within this capability. 43 | /// 44 | /// [eip-7702]: https://eips.ethereum.org/EIPS/eip-7702 45 | #[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize)] 46 | pub struct DelegationCapability { 47 | /// A list of valid delegation contracts. 48 | pub addresses: Vec
, 49 | } 50 | 51 | /// Wallet capabilities for a specific chain. 52 | #[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize)] 53 | pub struct Capabilities { 54 | /// The capability to delegate. 55 | pub delegation: DelegationCapability, 56 | } 57 | 58 | /// A map of wallet capabilities per chain ID. 59 | #[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize)] 60 | pub struct WalletCapabilities(pub HashMap); 61 | 62 | impl WalletCapabilities { 63 | /// Get the capabilities of the wallet API for the specified chain ID. 64 | pub fn get(&self, chain_id: ChainId) -> Option<&Capabilities> { 65 | self.0.get(&chain_id) 66 | } 67 | } 68 | 69 | /// AlphaNet `wallet_` RPC namespace. 70 | #[cfg_attr(not(test), rpc(server, namespace = "wallet"))] 71 | #[cfg_attr(test, rpc(server, client, namespace = "wallet"))] 72 | pub trait AlphaNetWalletApi { 73 | /// Get the capabilities of the wallet. 74 | /// 75 | /// Currently the only capability is [`DelegationCapability`]. 76 | /// 77 | /// See also [EIP-5792][eip-5792]. 78 | /// 79 | /// [eip-5792]: https://eips.ethereum.org/EIPS/eip-5792 80 | #[method(name = "getCapabilities")] 81 | fn get_capabilities(&self) -> RpcResult; 82 | 83 | /// Send a sequencer-sponsored transaction. 84 | /// 85 | /// The transaction will only be processed if: 86 | /// 87 | /// - The transaction is an [EIP-7702][eip-7702] transaction that delegates to one of the 88 | /// addresses listed in [`DelegationCapability`] (see [`Self::get_capabilities`]) 89 | /// - The transaction is an [EIP-1559][eip-1559] transaction to an EOA that is currently 90 | /// delegated to one of the addresses above 91 | /// - The value in the transaction is exactly 0. 92 | /// 93 | /// The sequencer will sign the transaction and inject it into the transaction pool, provided it 94 | /// is valid. The nonce is managed by the sequencer. 95 | /// 96 | /// [eip-7702]: https://eips.ethereum.org/EIPS/eip-7702 97 | /// [eip-1559]: https://eips.ethereum.org/EIPS/eip-1559 98 | #[method(name = "sendTransaction")] 99 | async fn send_transaction(&self, request: TransactionRequest) -> RpcResult; 100 | } 101 | 102 | /// Errors returned by the wallet API. 103 | #[derive(Debug, thiserror::Error)] 104 | pub enum AlphaNetWalletError { 105 | /// The transaction value is not 0. 106 | /// 107 | /// The value should be 0 to prevent draining the sequencer. 108 | #[error("tx value not zero")] 109 | ValueNotZero, 110 | /// The from field is set on the transaction. 111 | /// 112 | /// Requests with the from field are rejected, since it is implied that it will always be the 113 | /// sequencer. 114 | #[error("tx from field is set")] 115 | FromSet, 116 | /// The nonce field is set on the transaction. 117 | /// 118 | /// Requests with the nonce field set are rejected, as this is managed by the sequencer. 119 | #[error("tx nonce is set")] 120 | NonceSet, 121 | /// An authorization item was invalid. 122 | /// 123 | /// The item is invalid if it tries to delegate an account to a contract that is not 124 | /// whitelisted. 125 | #[error("invalid authorization address")] 126 | InvalidAuthorization, 127 | /// The to field of the transaction was invalid. 128 | /// 129 | /// The destination is invalid if: 130 | /// 131 | /// - There is no bytecode at the destination, or 132 | /// - The bytecode is not an EIP-7702 delegation designator, or 133 | /// - The delegation designator points to a contract that is not whitelisted 134 | #[error("the destination of the transaction is not a delegated account")] 135 | IllegalDestination, 136 | /// The transaction request was invalid. 137 | /// 138 | /// This is likely an internal error, as most of the request is built by the sequencer. 139 | #[error("invalid tx request")] 140 | InvalidTransactionRequest, 141 | /// An internal error occurred. 142 | #[error("internal error")] 143 | InternalError, 144 | } 145 | 146 | impl From for jsonrpsee::types::error::ErrorObject<'static> { 147 | fn from(error: AlphaNetWalletError) -> Self { 148 | jsonrpsee::types::error::ErrorObject::owned::<()>( 149 | jsonrpsee::types::error::INVALID_PARAMS_CODE, 150 | error.to_string(), 151 | None, 152 | ) 153 | } 154 | } 155 | 156 | /// Implementation of the AlphaNet `wallet_` namespace. 157 | pub struct AlphaNetWallet { 158 | inner: Arc>, 159 | } 160 | 161 | impl AlphaNetWallet { 162 | /// Create a new AlphaNet wallet module. 163 | pub fn new( 164 | provider: Provider, 165 | wallet: EthereumWallet, 166 | eth_api: Eth, 167 | chain_id: ChainId, 168 | valid_designations: Vec
, 169 | ) -> Self { 170 | let inner = AlphaNetWalletInner { 171 | provider, 172 | wallet, 173 | eth_api, 174 | chain_id, 175 | capabilities: WalletCapabilities(HashMap::from_iter([( 176 | chain_id, 177 | Capabilities { delegation: DelegationCapability { addresses: valid_designations } }, 178 | )])), 179 | permit: Default::default(), 180 | }; 181 | Self { inner: Arc::new(inner) } 182 | } 183 | 184 | fn chain_id(&self) -> ChainId { 185 | self.inner.chain_id 186 | } 187 | } 188 | 189 | #[async_trait] 190 | impl AlphaNetWalletApiServer for AlphaNetWallet 191 | where 192 | Provider: StateProviderFactory + Send + Sync + 'static, 193 | Eth: FullEthApi + Send + Sync + 'static, 194 | { 195 | fn get_capabilities(&self) -> RpcResult { 196 | trace!(target: "rpc::wallet", "Serving wallet_getCapabilities"); 197 | Ok(self.inner.capabilities.clone()) 198 | } 199 | 200 | async fn send_transaction(&self, mut request: TransactionRequest) -> RpcResult { 201 | trace!(target: "rpc::wallet", ?request, "Serving wallet_sendTransaction"); 202 | 203 | // validate fields common to eip-7702 and eip-1559 204 | validate_tx_request(&request)?; 205 | 206 | let valid_delegations: &[Address] = self 207 | .inner 208 | .capabilities 209 | .get(self.chain_id()) 210 | .map(|caps| caps.delegation.addresses.as_ref()) 211 | .unwrap_or_default(); 212 | if let Some(authorizations) = &request.authorization_list { 213 | // check that all auth items delegate to a valid address 214 | if authorizations.iter().any(|auth| !valid_delegations.contains(&auth.address)) { 215 | return Err(AlphaNetWalletError::InvalidAuthorization.into()); 216 | } 217 | } 218 | 219 | // validate destination 220 | match (request.authorization_list.is_some(), request.to) { 221 | // if this is an eip-1559 tx, ensure that it is an account that delegates to a 222 | // whitelisted address 223 | (false, Some(TxKind::Call(addr))) => { 224 | let state = 225 | self.inner.provider.latest().map_err(|_| AlphaNetWalletError::InternalError)?; 226 | let delegated_address = state 227 | .account_code(addr) 228 | .ok() 229 | .flatten() 230 | .and_then(|code| match code.0 { 231 | Bytecode::Eip7702(code) => Some(code.address()), 232 | _ => None, 233 | }) 234 | .unwrap_or_default(); 235 | 236 | // not a whitelisted address, or not an eip-7702 bytecode 237 | if delegated_address == Address::ZERO 238 | || !valid_delegations.contains(&delegated_address) 239 | { 240 | return Err(AlphaNetWalletError::IllegalDestination.into()); 241 | } 242 | } 243 | // if it's an eip-7702 tx, let it through 244 | (true, _) => (), 245 | // create tx's disallowed 246 | _ => return Err(AlphaNetWalletError::IllegalDestination.into()), 247 | } 248 | 249 | // we acquire the permit here so that all following operations are performed exclusively 250 | let _permit = self.inner.permit.lock().await; 251 | 252 | // set nonce 253 | let tx_count = EthState::transaction_count( 254 | &self.inner.eth_api, 255 | NetworkWallet::::default_signer_address(&self.inner.wallet), 256 | Some(BlockId::pending()), 257 | ) 258 | .await 259 | .map_err(Into::into)?; 260 | request.nonce = Some(tx_count.to()); 261 | 262 | // set chain id 263 | request.chain_id = Some(self.chain_id()); 264 | 265 | // set gas limit 266 | let estimate = 267 | EthCall::estimate_gas_at(&self.inner.eth_api, request.clone(), BlockId::latest(), None) 268 | .await 269 | .map_err(Into::into)?; 270 | request = request.gas_limit(estimate.to()); 271 | 272 | // set gas fees 273 | let (base_fee, max_priority_fee_per_gas) = 274 | LoadFee::eip1559_fees(&self.inner.eth_api, None, None) 275 | .await 276 | .map_err(|_| AlphaNetWalletError::InvalidTransactionRequest)?; 277 | request.max_fee_per_gas = Some((base_fee + max_priority_fee_per_gas).to::() * 2u128); 278 | request.max_priority_fee_per_gas = Some((max_priority_fee_per_gas * U256::from(2)).to()); 279 | request.gas_price = None; 280 | 281 | // build and sign 282 | let envelope = 283 | >::build::( 284 | request, 285 | &self.inner.wallet, 286 | ) 287 | .await 288 | .map_err(|_| AlphaNetWalletError::InvalidTransactionRequest)?; 289 | 290 | // this uses the internal `OpEthApi` to either forward the tx to the sequencer, or add it to 291 | // the txpool 292 | // 293 | // see: https://github.com/paradigmxyz/reth/blob/b67f004fbe8e1b7c05f84f314c4c9f2ed9be1891/crates/optimism/rpc/src/eth/transaction.rs#L35-L57 294 | EthTransactions::send_raw_transaction(&self.inner.eth_api, envelope.encoded_2718().into()) 295 | .await 296 | .inspect_err(|err| warn!(target: "rpc::wallet", ?err, "Error adding sequencer-sponsored tx to pool")) 297 | .map_err(Into::into) 298 | } 299 | } 300 | 301 | /// Implementation of the AlphaNet `wallet_` namespace. 302 | struct AlphaNetWalletInner { 303 | provider: Provider, 304 | eth_api: Eth, 305 | wallet: EthereumWallet, 306 | chain_id: ChainId, 307 | capabilities: WalletCapabilities, 308 | /// Used to guard tx signing 309 | permit: Mutex<()>, 310 | } 311 | 312 | fn validate_tx_request(request: &TransactionRequest) -> Result<(), AlphaNetWalletError> { 313 | // reject transactions that have a non-zero value to prevent draining the sequencer. 314 | if request.value.is_some_and(|val| val > U256::ZERO) { 315 | return Err(AlphaNetWalletError::ValueNotZero); 316 | } 317 | 318 | // reject transactions that have from set, as this will be the sequencer. 319 | if request.from.is_some() { 320 | return Err(AlphaNetWalletError::FromSet); 321 | } 322 | 323 | // reject transaction requests that have nonce set, as this is managed by the sequencer. 324 | if request.nonce.is_some() { 325 | return Err(AlphaNetWalletError::NonceSet); 326 | } 327 | 328 | Ok(()) 329 | } 330 | 331 | #[cfg(test)] 332 | mod tests { 333 | mod types { 334 | use crate::{Capabilities, DelegationCapability, WalletCapabilities}; 335 | use alloy_primitives::{address, map::HashMap}; 336 | 337 | #[test] 338 | fn ser() { 339 | let caps = WalletCapabilities(HashMap::from_iter([( 340 | 0x69420, 341 | Capabilities { 342 | delegation: DelegationCapability { 343 | addresses: vec![address!("90f79bf6eb2c4f870365e785982e1f101e93b906")], 344 | }, 345 | }, 346 | )])); 347 | assert_eq!(serde_json::to_string(&caps).unwrap(), "{\"431136\":{\"delegation\":{\"addresses\":[\"0x90f79bf6eb2c4f870365e785982e1f101e93b906\"]}}}"); 348 | } 349 | 350 | #[test] 351 | fn de() { 352 | let caps: WalletCapabilities = serde_json::from_str( 353 | r#"{ 354 | "431136": { 355 | "delegation": { 356 | "addresses": ["0x90f79bf6eb2c4f870365e785982e1f101e93b906"] 357 | } 358 | } 359 | }"#, 360 | ) 361 | .expect("could not deser"); 362 | 363 | assert_eq!( 364 | caps, 365 | WalletCapabilities(HashMap::from_iter([( 366 | 0x69420, 367 | Capabilities { 368 | delegation: DelegationCapability { 369 | addresses: vec![address!("90f79bf6eb2c4f870365e785982e1f101e93b906")], 370 | }, 371 | }, 372 | )])) 373 | ); 374 | } 375 | } 376 | } 377 | -------------------------------------------------------------------------------- /deny.toml: -------------------------------------------------------------------------------- 1 | [advisories] 2 | vulnerability = "deny" 3 | unmaintained = "warn" 4 | unsound = "warn" 5 | yanked = "warn" 6 | notice = "warn" 7 | 8 | [bans] 9 | multiple-versions = "warn" 10 | wildcards = "deny" 11 | highlight = "all" 12 | 13 | [licenses] 14 | unlicensed = "deny" 15 | confidence-threshold = 0.9 16 | # copyleft = "deny" 17 | 18 | allow = [ 19 | "MIT", 20 | "MIT-0", 21 | "Apache-2.0", 22 | "Apache-2.0 WITH LLVM-exception", 23 | "BSD-2-Clause", 24 | "BSD-3-Clause", 25 | "ISC", 26 | "Unicode-DFS-2016", 27 | "Unlicense", 28 | "MPL-2.0", 29 | # https://github.com/briansmith/ring/issues/902 30 | "LicenseRef-ring", 31 | # https://github.com/briansmith/webpki/issues/148 32 | "LicenseRef-webpki", 33 | ] 34 | 35 | exceptions = [ 36 | # CC0 is a permissive license but somewhat unclear status for source code 37 | # so we prefer to not have dependencies using it 38 | # https://tldrlegal.com/license/creative-commons-cc0-1.0-universal 39 | { allow = ["CC0-1.0"], name = "tiny-keccak" }, 40 | ] 41 | 42 | [[licenses.clarify]] 43 | name = "ring" 44 | expression = "LicenseRef-ring" 45 | license-files = [{ path = "LICENSE", hash = 0xbd0eed23 }] 46 | 47 | [[licenses.clarify]] 48 | name = "webpki" 49 | expression = "LicenseRef-webpki" 50 | license-files = [{ path = "LICENSE", hash = 0x001c7e6c }] 51 | 52 | [sources] 53 | unknown-registry = "deny" 54 | unknown-git = "deny" 55 | -------------------------------------------------------------------------------- /etc/alphanet-rollup.json: -------------------------------------------------------------------------------- 1 | { 2 | "genesis": { 3 | "l1": { 4 | "hash": "0x55e9e708816e7f896bdff6abe9338e8866384fcd26151f5d4fb5f7722aaef745", 5 | "number": 5630263 6 | }, 7 | "l2": { 8 | "hash": "0xd956d869975b1c681aab2fcb6d278babb8133bfa1d8cf860eca5f26cd56ed841", 9 | "number": 0 10 | }, 11 | "l2_time": 1712269308, 12 | "system_config": { 13 | "batcherAddr": "0x7dc3bb98f6627a3a845448b022f9fcb37417a9b3", 14 | "overhead": "0x0000000000000000000000000000000000000000000000000000000000000834", 15 | "scalar": "0x00000000000000000000000000000000000000000000000000000000000f4240", 16 | "gasLimit": 30000000 17 | } 18 | }, 19 | "block_time": 2, 20 | "max_sequencer_drift": 600, 21 | "seq_window_size": 3600, 22 | "channel_timeout": 300, 23 | "l1_chain_id": 11155111, 24 | "l2_chain_id": 41144114, 25 | "regolith_time": 0, 26 | "batch_inbox_address": "0xff00000000000000000000000000000041144114", 27 | "deposit_contract_address": "0xe2c551065382c9b7a2cc1c61e69ac1cb45282e92", 28 | "l1_system_config_address": "0xa3cf7ce36373b7cf0c6cfd42736426d8420a6df9" 29 | } 30 | -------------------------------------------------------------------------------- /etc/deploy-config/sepolia.json: -------------------------------------------------------------------------------- 1 | { 2 | "numDeployConfirmations": 1, 3 | "finalSystemOwner": "0x76B05DF1C03ec55AD16683be08D7A1f319598BD7", 4 | "portalGuardian": "0x76B05DF1C03ec55AD16683be08D7A1f319598BD7", 5 | "controller": "0x76B05DF1C03ec55AD16683be08D7A1f319598BD7", 6 | "l1StartingBlockTag": "0x55e9e708816e7f896bdff6abe9338e8866384fcd26151f5d4fb5f7722aaef745", 7 | "l1ChainID": 11155111, 8 | "l2ChainID": 41144114, 9 | "l2BlockTime": 2, 10 | "maxSequencerDrift": 600, 11 | "sequencerWindowSize": 3600, 12 | "channelTimeout": 300, 13 | "p2pSequencerAddress": "0xbF6860D64Eee174C7e178c656aC045c7951544C4", 14 | "batchInboxAddress": "0xff00000000000000000000000000000041144114", 15 | "batchSenderAddress": "0x7dC3bb98F6627a3a845448B022F9Fcb37417A9b3", 16 | "l2OutputOracleSubmissionInterval": 120, 17 | "l2OutputOracleStartingBlockNumber": 0, 18 | "l2OutputOracleStartingTimestamp": 1712269308, 19 | "l2OutputOracleProposer": "0x94b0901032205D65a9Ff9BDB38ECc86b01b7A47b", 20 | "l2OutputOracleChallenger": "0x94b0901032205D65a9Ff9BDB38ECc86b01b7A47b", 21 | "finalizationPeriodSeconds": 12, 22 | "proxyAdminOwner": "0x94b0901032205D65a9Ff9BDB38ECc86b01b7A47b", 23 | "baseFeeVaultRecipient": "0x94b0901032205D65a9Ff9BDB38ECc86b01b7A47b", 24 | "l1FeeVaultRecipient": "0x94b0901032205D65a9Ff9BDB38ECc86b01b7A47b", 25 | "sequencerFeeVaultRecipient": "0x94b0901032205D65a9Ff9BDB38ECc86b01b7A47b", 26 | "baseFeeVaultMinimumWithdrawalAmount": "0x8ac7230489e80000", 27 | "l1FeeVaultMinimumWithdrawalAmount": "0x8ac7230489e80000", 28 | "sequencerFeeVaultMinimumWithdrawalAmount": "0x8ac7230489e80000", 29 | "baseFeeVaultWithdrawalNetwork": 0, 30 | "l1FeeVaultWithdrawalNetwork": 0, 31 | "sequencerFeeVaultWithdrawalNetwork": 0, 32 | "gasPriceOracleOverhead": 2100, 33 | "gasPriceOracleScalar": 1000000, 34 | "enableGovernance": true, 35 | "governanceTokenSymbol": "OP", 36 | "governanceTokenName": "Optimism", 37 | "governanceTokenOwner": "0x94b0901032205D65a9Ff9BDB38ECc86b01b7A47b", 38 | "l2GenesisBlockGasLimit": "0x1c9c380", 39 | "l2GenesisBlockBaseFeePerGas": "0x3b9aca00", 40 | "l2GenesisRegolithTimeOffset": "0x0", 41 | "eip1559Denominator": 50, 42 | "eip1559Elasticity": 10 43 | } 44 | -------------------------------------------------------------------------------- /etc/dev-genesis.json: -------------------------------------------------------------------------------- 1 | { 2 | "config": { 3 | "chainId": 41144114, 4 | "homesteadBlock": 0, 5 | "eip150Block": 0, 6 | "eip155Block": 0, 7 | "eip158Block": 0, 8 | "byzantiumBlock": 0, 9 | "constantinopleBlock": 0, 10 | "petersburgBlock": 0, 11 | "istanbulBlock": 0, 12 | "muirGlacierBlock": 0, 13 | "berlinBlock": 0, 14 | "londonBlock": 0, 15 | "arrowGlacierBlock": 0, 16 | "grayGlacierBlock": 0, 17 | "mergeNetsplitBlock": 0, 18 | "bedrockBlock": 0, 19 | "regolithTime": 0, 20 | "ecotoneTime": 0, 21 | "pragueTime": 0, 22 | "terminalTotalDifficulty": 0, 23 | "terminalTotalDifficultyPassed": true, 24 | "optimism": { 25 | "eip1559Elasticity": 10, 26 | "eip1559Denominator": 50, 27 | "eip1559DenominatorCanyon": 0 28 | } 29 | }, 30 | "nonce": "0x0", 31 | "timestamp": "0x6490fdd2", 32 | "extraData": "0x", 33 | "gasLimit": "0x1c9c380", 34 | "difficulty": "0x0", 35 | "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", 36 | "coinbase": "0x0000000000000000000000000000000000000000", 37 | "stateRoot": "0x5eb6e371a698b8d68f665192350ffcecbbbf322916f4b51bd79bb6887da3f494", 38 | "alloc": { 39 | "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266": { 40 | "balance": "0xD3C21BCECCEDA1000000" 41 | }, 42 | "0x70997970C51812dc3A010C7d01b50e0d17dc79C8": { 43 | "balance": "0xD3C21BCECCEDA1000000" 44 | }, 45 | "0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC": { 46 | "balance": "0xD3C21BCECCEDA1000000" 47 | }, 48 | "0x90F79bf6EB2c4f870365E785982E1f101E93b906": { 49 | "balance": "0xD3C21BCECCEDA1000000" 50 | }, 51 | "0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65": { 52 | "balance": "0xD3C21BCECCEDA1000000" 53 | }, 54 | "0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc": { 55 | "balance": "0xD3C21BCECCEDA1000000" 56 | }, 57 | "0x976EA74026E726554dB657fA54763abd0C3a0aa9": { 58 | "balance": "0xD3C21BCECCEDA1000000" 59 | }, 60 | "0x14dC79964da2C08b23698B3D3cc7Ca32193d9955": { 61 | "balance": "0xD3C21BCECCEDA1000000" 62 | }, 63 | "0x23618e81E3f5cdF7f54C3d65f7FBc0aBf5B21E8f": { 64 | "balance": "0xD3C21BCECCEDA1000000" 65 | }, 66 | "0xa0Ee7A142d267C1f36714E4a8F75612F20a79720": { 67 | "balance": "0xD3C21BCECCEDA1000000" 68 | }, 69 | "0xBcd4042DE499D14e55001CcbB24a551F3b954096": { 70 | "balance": "0xD3C21BCECCEDA1000000" 71 | }, 72 | "0x71bE63f3384f5fb98995898A86B02Fb2426c5788": { 73 | "balance": "0xD3C21BCECCEDA1000000" 74 | }, 75 | "0xFABB0ac9d68B0B445fB7357272Ff202C5651694a": { 76 | "balance": "0xD3C21BCECCEDA1000000" 77 | }, 78 | "0x1CBd3b2770909D4e10f157cABC84C7264073C9Ec": { 79 | "balance": "0xD3C21BCECCEDA1000000" 80 | }, 81 | "0xdF3e18d64BC6A983f673Ab319CCaE4f1a57C7097": { 82 | "balance": "0xD3C21BCECCEDA1000000" 83 | }, 84 | "0xcd3B766CCDd6AE721141F452C550Ca635964ce71": { 85 | "balance": "0xD3C21BCECCEDA1000000" 86 | }, 87 | "0x2546BcD3c84621e976D8185a91A922aE77ECEc30": { 88 | "balance": "0xD3C21BCECCEDA1000000" 89 | }, 90 | "0xbDA5747bFD65F08deb54cb465eB87D40e51B197E": { 91 | "balance": "0xD3C21BCECCEDA1000000" 92 | }, 93 | "0xdD2FD4581271e230360230F9337D5c0430Bf44C0": { 94 | "balance": "0xD3C21BCECCEDA1000000" 95 | }, 96 | "0x8626f6940E2eb28930eFb4CeF49B2d1F2C9C1199": { 97 | "balance": "0xD3C21BCECCEDA1000000" 98 | } 99 | }, 100 | "number": "0x0", 101 | "gasUsed": "0x0", 102 | "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000" 103 | } 104 | -------------------------------------------------------------------------------- /etc/kurtosis.yaml: -------------------------------------------------------------------------------- 1 | ethereum_package: 2 | participants: 3 | - el_type: reth 4 | cl_type: lighthouse 5 | optimism_package: 6 | participants: 7 | - el_type: op-reth 8 | el_image: ghcr.io/paradigmxyz/alphanet:latest 9 | count: 2 10 | network_params: 11 | network_id: "41144114" 12 | seconds_per_slot: 1 13 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | merge_derives = false 2 | reorder_imports = true 3 | use_field_init_shorthand = true 4 | use_small_heuristics = "Max" 5 | 6 | # Nightly 7 | max_width = 100 8 | comment_width = 100 9 | imports_granularity = "Crate" 10 | wrap_comments = true 11 | format_code_in_doc_comments = true 12 | doc_comment_code_block_width = 100 13 | format_macro_matchers = true 14 | --------------------------------------------------------------------------------