diff --git a/.github/workflows/publish-pythnet-stylus-sdk.yml b/.github/workflows/publish-pythnet-stylus-sdk.yml new file mode 100644 index 0000000000..d1b9458c7f --- /dev/null +++ b/.github/workflows/publish-pythnet-stylus-sdk.yml @@ -0,0 +1,20 @@ +name: Publish Pyth Stylus SDK to crates.io + +on: + push: + tags: + - pythnet-stylus-sdk-v* +# jobs: +# publish-pythnet-sdk: +# name: Publish Pythnet SDK +# runs-on: ubuntu-latest +# steps: +# - name: Checkout sources +# uses: actions/checkout@v2 + +# - run: cargo publish --token ${CARGO_REGISTRY_TOKEN} +# env: +# CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} +# working-directory: "pythnet/pythnet_sdk" + +#Just seetinh up this script \ No newline at end of file diff --git a/.gitmodules b/.gitmodules index 5032d7daf3..7faad81e8b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,9 +1,19 @@ -[submodule "lazer/contracts/evm/lib/forge-std"] - path = lazer/contracts/evm/lib/forge-std + +[submodule "lib/forge-std"] + path = lib/forge-std url = https://github.com/foundry-rs/forge-std -[submodule "lazer/contracts/evm/lib/openzeppelin-contracts-upgradeable"] - path = lazer/contracts/evm/lib/openzeppelin-contracts-upgradeable +[submodule "lib/openzeppelin-foundry-upgrades"] + path = lib/openzeppelin-foundry-upgrades + url = https://github.com/OpenZeppelin/openzeppelin-foundry-upgrades +[submodule "lib/openzeppelin-contracts-upgradeable"] + path = lib/openzeppelin-contracts-upgradeable url = https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable +[submodule "target_chains/ethereum/sdk/stylus/pyth-mock-solidity/lib/forge-std"] + path = target_chains/ethereum/sdk/stylus/pyth-mock-solidity/lib/forge-std + url = https://github.com/foundry-rs/forge-std +[submodule "target_chains/ethereum/sdk/stylus/pyth-mock-solidity/lib/openzeppelin-foundry-upgrades"] + path = target_chains/ethereum/sdk/stylus/pyth-mock-solidity/lib/openzeppelin-foundry-upgrades + url = https://github.com/OpenZeppelin/openzeppelin-foundry-upgrades [submodule "lazer/contracts/evm/lib/openzeppelin-contracts"] path = lazer/contracts/evm/lib/openzeppelin-contracts url = https://github.com/OpenZeppelin/openzeppelin-contracts diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6cf9138762..732d3ce6ce 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -163,3 +163,15 @@ repos: entry: cargo +1.82.0 clippy --manifest-path ./lazer/Cargo.toml --all-targets -- --deny warnings pass_filenames: false files: lazer + - id: cargo-fmt-stylus-sdk + name: Cargo format for Stylus SDK + language: "rust" + entry: cargo +1.82.0 fmt --manifest-path ./target_chains/ethereum/sdk/stylus/Cargo.toml --all + pass_filenames: false + files: target_chains/ethereum/sdk/stylus + - id: cargo-clippy-stylus-sdk + name: Cargo clippy for Stylus SDK + language: "rust" + entry: cargo +1.82.0 clippy --manifest-path ./target_chains/ethereum/sdk/stylus/Cargo.toml --all-targets -- --deny warnings + pass_filenames: false + files: target_chains/ethereum/sdk/stylus diff --git a/lib/forge-std b/lib/forge-std new file mode 160000 index 0000000000..1eea5bae12 --- /dev/null +++ b/lib/forge-std @@ -0,0 +1 @@ +Subproject commit 1eea5bae12ae557d589f9f0f0edae2faa47cb262 diff --git a/lib/openzeppelin-contracts-upgradeable b/lib/openzeppelin-contracts-upgradeable new file mode 160000 index 0000000000..2d081f24ca --- /dev/null +++ b/lib/openzeppelin-contracts-upgradeable @@ -0,0 +1 @@ +Subproject commit 2d081f24cac1a867f6f73d512f2022e1fa987854 diff --git a/lib/openzeppelin-foundry-upgrades b/lib/openzeppelin-foundry-upgrades new file mode 160000 index 0000000000..16e0ae21e0 --- /dev/null +++ b/lib/openzeppelin-foundry-upgrades @@ -0,0 +1 @@ +Subproject commit 16e0ae21e0e39049f619f2396fa28c57fad07368 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 1f5361c18e..d4eff6b057 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -19,6 +19,7 @@ packages: - "target_chains/ethereum/entropy_sdk/solidity" - "target_chains/ethereum/sdk/js" - "target_chains/ethereum/sdk/solidity" + - "target_chains/ethereum/sdk/stylus/pyth-mock-solidity" - "target_chains/ethereum/examples/coin_flip/app" - "target_chains/fuel/sdk/js" - "target_chains/starknet/sdk/js" @@ -44,6 +45,7 @@ catalog: "@next/third-parties": 15.0.2 "@phosphor-icons/react": 2.1.7 "@pythnetwork/client": 2.22.0 + "@pythnetwork/pyth-sdk-solidity": 4.0.0 "@react-hookz/web": 24.0.4 "@solana/web3.js": 1.95.4 "@storybook/addon-essentials": 8.3.5 diff --git a/target_chains/ethereum/sdk/stylus/.cargo/config.toml b/target_chains/ethereum/sdk/stylus/.cargo/config.toml new file mode 100644 index 0000000000..77cf9f2648 --- /dev/null +++ b/target_chains/ethereum/sdk/stylus/.cargo/config.toml @@ -0,0 +1,8 @@ +[target.wasm32-unknown-unknown] +rustflags = ["-C", "link-arg=-zstack-size=8192"] + +[target.aarch64-apple-darwin] +rustflags = ["-C", "link-arg=-undefined", "-C", "link-arg=dynamic_lookup"] + +[target.x86_64-apple-darwin] +rustflags = ["-C", "link-arg=-undefined", "-C", "link-arg=dynamic_lookup"] diff --git a/target_chains/ethereum/sdk/stylus/.github/workflows/check-wasm.yml b/target_chains/ethereum/sdk/stylus/.github/workflows/check-wasm.yml new file mode 100644 index 0000000000..f27d7b991b --- /dev/null +++ b/target_chains/ethereum/sdk/stylus/.github/workflows/check-wasm.yml @@ -0,0 +1,36 @@ +name: check-wasm +# This workflow checks that the compiled wasm binary of every example contract +# can be deployed to Arbitrum Stylus. +on: + pull_request: + paths: + - target_chains/ethereum/sdk/stylus/** ** + push: + branches: + - main + paths: + - target_chains/ethereum/sdk/stylus/** +permissions: + contents: read +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true +env: + CARGO_TERM_COLOR: always +jobs: + check-wasm: + name: Check WASM binary + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Install rust + uses: actions-rust-lang/setup-rust-toolchain@v1 + with: + rustflags: "" + + - name: Install cargo-stylus + run: cargo install cargo-stylus@0.5.3 + + - name: Run wasm check + run: ./scripts/check-wasm.sh diff --git a/target_chains/ethereum/sdk/stylus/.github/workflows/check.yml b/target_chains/ethereum/sdk/stylus/.github/workflows/check.yml new file mode 100644 index 0000000000..dbe4fdd6e9 --- /dev/null +++ b/target_chains/ethereum/sdk/stylus/.github/workflows/check.yml @@ -0,0 +1,132 @@ +name: check +# This workflow runs whenever a PR is opened or updated, or a commit is pushed +# to main. It runs several checks: +# - fmt: checks that the code is formatted according to `rustfmt`. +# - clippy: checks that the code does not contain any `clippy` warnings. +# - doc: checks that the code can be documented without errors. +# - hack: check combinations of feature flags. +# - typos: checks for typos across the repo. +permissions: + contents: read +# This configuration allows maintainers of this repo to create a branch and +# pull request based on the new branch. Restricting the push trigger to the +# main branch ensures that the PR only gets built once. +on: + pull_request: + paths: + - target_chains/ethereum/sdk/stylus/** ** + push: + branches: + - main + paths: + - target_chains/ethereum/sdk/stylus/** +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true +env: + CARGO_TERM_COLOR: always +jobs: + fmt: + runs-on: ubuntu-latest + name: nightly / fmt + steps: + - uses: actions/checkout@v4 + with: + submodules: true + + - name: Install rust + # We run in nightly to make use of some features only available there. + # Check out `rustfmt.toml` to see which ones. + uses: actions-rust-lang/setup-rust-toolchain@v1 + with: + toolchain: nightly + components: rustfmt + rustflags: "" + + - name: Check formatting + run: cargo fmt --all --check + clippy: + runs-on: ubuntu-latest + name: ${{ matrix.toolchain }} / clippy + permissions: + contents: read + checks: write + strategy: + fail-fast: false + matrix: + # Get early warning of new lints which are regularly introduced in beta + # channels. + toolchain: [ stable, beta ] + steps: + - uses: actions/checkout@v4 + with: + submodules: true + + - name: Install rust ${{ matrix.toolchain }} + uses: actions-rust-lang/setup-rust-toolchain@v1 + with: + toolchain: ${{ matrix.toolchain }} + components: clippy + rustflags: "" + + - name: Cargo clippy + uses: giraffate/clippy-action@v1 + with: + reporter: 'github-pr-check' + github_token: ${{ secrets.GITHUB_TOKEN }} + doc: + # Run docs generation on nightly rather than stable. This enables features + # like https://doc.rust-lang.org/beta/unstable-book/language-features/doc-cfg.html + # which allows an API be documented as only available in some specific + # platforms. + runs-on: ubuntu-latest + name: nightly / doc + steps: + - uses: actions/checkout@v4 + with: + submodules: true + + - name: Install rust + uses: actions-rust-lang/setup-rust-toolchain@v1 + with: + toolchain: nightly + rustflags: "" + + - name: Cargo doc + run: cargo doc --no-deps --all-features + env: + RUSTDOCFLAGS: --cfg docsrs + hack: + # `cargo-hack` checks combinations of feature flags to ensure that features + # are all additive which is required for feature unification. + runs-on: ubuntu-latest + name: ubuntu / stable / features + steps: + - uses: actions/checkout@v4 + with: + submodules: true + + - name: Install rust + uses: actions-rust-lang/setup-rust-toolchain@v1 + with: + toolchain: stable + target: wasm32-unknown-unknown + rustflags: "" + + - name: Cargo install cargo-hack + uses: taiki-e/install-action@cargo-hack + # Intentionally no target specifier; see https://github.com/jonhoo/rust-ci-conf/pull/4 + # `--feature-powerset` runs for every combination of features. Note that + # target in this context means one of `--lib`, `--bin`, etc, and not the + # target triple. + - name: Cargo hack + run: cargo hack check --feature-powerset --depth 2 --release --target wasm32-unknown-unknown --skip std --workspace --exclude e2e --exclude basic-example-script --exclude benches + typos: + runs-on: ubuntu-latest + name: ubuntu / stable / typos + steps: + - name: Checkout Actions Repository + uses: actions/checkout@v4 + + - name: Check spelling of files in the workspace + uses: crate-ci/typos@v1.27.3 diff --git a/target_chains/ethereum/sdk/stylus/.github/workflows/e2e-tests.yml b/target_chains/ethereum/sdk/stylus/.github/workflows/e2e-tests.yml new file mode 100644 index 0000000000..d7ba3b1a6f --- /dev/null +++ b/target_chains/ethereum/sdk/stylus/.github/workflows/e2e-tests.yml @@ -0,0 +1,52 @@ +# This workflow runs our end-to-end tests suite. +# +# It roughly follows these steps: +# - Install rust +# - Install `cargo-stylus` +# - Install `solc` +# - Spin up `nitro-testnode` +# +# Contract deployments and account funding happen on a per-test basis. +name: e2e +permissions: + contents: read +on: + pull_request: + paths: + - target_chains/ethereum/sdk/stylus/** ** + push: + branches: + - main + paths: + - target_chains/ethereum/sdk/stylus/** +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true +env: + CARGO_TERM_COLOR: always +jobs: + required: + name: tests + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Install rust + uses: actions-rust-lang/setup-rust-toolchain@v1 + with: + cache-key: "e2e-tests" + rustflags: "" + + - name: Install cargo-stylus + run: cargo install cargo-stylus@0.5.3 + + - name: Install solc + run: | + curl -LO https://github.com/ethereum/solidity/releases/download/v0.8.24/solc-static-linux + sudo mv solc-static-linux /usr/bin/solc + sudo chmod a+x /usr/bin/solc + + - name: Setup nitro node + run: ./scripts/nitro-testnode.sh -d -i + - name: run integration tests + run: ./scripts/e2e-tests.sh diff --git a/target_chains/ethereum/sdk/stylus/.github/workflows/foundry-test.yml b/target_chains/ethereum/sdk/stylus/.github/workflows/foundry-test.yml new file mode 100644 index 0000000000..22b79ce3e0 --- /dev/null +++ b/target_chains/ethereum/sdk/stylus/.github/workflows/foundry-test.yml @@ -0,0 +1,47 @@ +name: foundry-test + +on: + pull_request: + paths: + - target_chains/ethereum/sdk/stylus/** ** + push: + branches: + - main + paths: + - target_chains/ethereum/sdk/stylus/** + +env: + FOUNDRY_PROFILE: ci + +jobs: + check: + name: Foundry project + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1 + with: + version: nightly + + - name: Show Forge version + run: forge --version + + - name: Change directory to pyth-mock-solidity + run: cd pyth-mock-solidity + + - name: Run Forge fmt + run: forge fmt --check + id: fmt + + - name: Run Forge build + run: forge build --sizes + id: build + + - name: Run Forge tests + run: forge test -vvv + id: test diff --git a/target_chains/ethereum/sdk/stylus/.github/workflows/gas-bench.yml b/target_chains/ethereum/sdk/stylus/.github/workflows/gas-bench.yml new file mode 100644 index 0000000000..cdb768bcc6 --- /dev/null +++ b/target_chains/ethereum/sdk/stylus/.github/workflows/gas-bench.yml @@ -0,0 +1,45 @@ +name: gas-bench +# This workflow checks that the compiled wasm binary of every example contract +# can be deployed to Arbitrum Stylus. +permissions: + contents: read +on: + pull_request: + paths: + - target_chains/ethereum/sdk/stylus/** ** + push: + branches: + - main + paths: + - target_chains/ethereum/sdk/stylus/** +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true +env: + CARGO_TERM_COLOR: always +jobs: + required: + name: Gas usage report + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Install rust + uses: actions-rust-lang/setup-rust-toolchain@v1 + with: + cache-key: "gas-bench" + rustflags: "" + + - name: Install cargo-stylus + run: cargo install cargo-stylus@0.5.3 + + - name: Install solc + run: | + curl -LO https://github.com/ethereum/solidity/releases/download/v0.8.24/solc-static-linux + sudo mv solc-static-linux /usr/bin/solc + sudo chmod a+x /usr/bin/solc + + - name: Setup nitro node + run: ./scripts/nitro-testnode.sh -d -i + - name: run benches + run: ./scripts/bench.sh diff --git a/target_chains/ethereum/sdk/stylus/.github/workflows/nostd.yml b/target_chains/ethereum/sdk/stylus/.github/workflows/nostd.yml new file mode 100644 index 0000000000..39d30717e8 --- /dev/null +++ b/target_chains/ethereum/sdk/stylus/.github/workflows/nostd.yml @@ -0,0 +1,43 @@ +# This workflow checks whether the library is able to run without the std +# library. See `check.yml` for information about how the concurrency +# cancellation and workflow triggering works. +name: no-std +permissions: + contents: read +on: + pull_request: + paths: + - target_chains/ethereum/sdk/stylus/** ** + push: + branches: + - main + paths: + - target_chains/ethereum/sdk/stylus/** +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true +env: + CARGO_TERM_COLOR: always +jobs: + nostd: + runs-on: ubuntu-latest + name: ${{ matrix.target }} + strategy: + matrix: + target: [ wasm32-unknown-unknown ] + steps: + - uses: actions/checkout@v4 + with: + submodules: true + + - name: Install rust + uses: actions-rust-lang/setup-rust-toolchain@v1 + with: + toolchain: stable + rustflags: "" + + - name: Add rust targets ${{ matrix.target }} + run: rustup target add ${{ matrix.target }} + + - name: Cargo check + run: cargo check --release --target ${{ matrix.target }} --no-default-features diff --git a/target_chains/ethereum/sdk/stylus/.gitignore b/target_chains/ethereum/sdk/stylus/.gitignore new file mode 100644 index 0000000000..28adb4fad7 --- /dev/null +++ b/target_chains/ethereum/sdk/stylus/.gitignore @@ -0,0 +1,11 @@ +/target + +.env + +**/node_modules/ + +docs/build/ + +**/.DS_Store + +**/nitro-testnode diff --git a/target_chains/ethereum/sdk/stylus/Cargo.lock b/target_chains/ethereum/sdk/stylus/Cargo.lock new file mode 100644 index 0000000000..a9d7082a4c --- /dev/null +++ b/target_chains/ethereum/sdk/stylus/Cargo.lock @@ -0,0 +1,4416 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +dependencies = [ + "gimli 0.29.0", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if 1.0.0", + "cipher", + "cpufeatures", +] + +[[package]] +name = "ahash" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if 1.0.0", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" + +[[package]] +name = "alloy" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ba1c79677c9ce51c8d45e20845b05e6fb070ea2c863fba03ad6af2c778474bd" +dependencies = [ + "alloy-consensus", + "alloy-contract", + "alloy-core", + "alloy-eips", + "alloy-genesis", + "alloy-network", + "alloy-provider", + "alloy-rpc-client", + "alloy-rpc-types", + "alloy-serde", + "alloy-signer", + "alloy-signer-local", + "alloy-transport", + "alloy-transport-http", +] + +[[package]] +name = "alloy-chains" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1752d7d62e2665da650a36d84abbf239f812534475d51f072a49a533513b7cdd" +dependencies = [ + "num_enum", + "strum", +] + +[[package]] +name = "alloy-consensus" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f63a6c9eb45684a5468536bc55379a2af0f45ffa5d756e4e4964532737e1836" +dependencies = [ + "alloy-eips", + "alloy-primitives", + "alloy-rlp", + "alloy-serde", + "c-kzg", + "serde", +] + +[[package]] +name = "alloy-contract" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c26b7d34cb76f826558e9409a010e25257f7bfb5aa5e3dd0042c564664ae159" +dependencies = [ + "alloy-dyn-abi", + "alloy-json-abi", + "alloy-network", + "alloy-primitives", + "alloy-provider", + "alloy-rpc-types-eth", + "alloy-sol-types", + "alloy-transport", + "futures", + "futures-util", + "thiserror", +] + +[[package]] +name = "alloy-core" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5af3faff14c12c8b11037e0a093dd157c3702becb8435577a2408534d0758315" +dependencies = [ + "alloy-dyn-abi", + "alloy-json-abi", + "alloy-primitives", + "alloy-sol-types", +] + +[[package]] +name = "alloy-dyn-abi" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb6e6436a9530f25010d13653e206fab4c9feddacf21a54de8d7311b275bc56b" +dependencies = [ + "alloy-json-abi", + "alloy-primitives", + "alloy-sol-type-parser", + "alloy-sol-types", + "const-hex", + "itoa", + "serde", + "serde_json", + "winnow 0.6.13", +] + +[[package]] +name = "alloy-eips" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa4b0fc6a572ef2eebda0a31a5e393d451abda703fec917c75d9615d8c978cf2" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "alloy-serde", + "c-kzg", + "once_cell", + "serde", + "sha2", +] + +[[package]] +name = "alloy-genesis" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48450f9c6f0821c1eee00ed912942492ed4f11dd69532825833de23ecc7a2256" +dependencies = [ + "alloy-primitives", + "alloy-serde", + "serde", +] + +[[package]] +name = "alloy-json-abi" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aaeaccd50238126e3a0ff9387c7c568837726ad4f4e399b528ca88104d6c25ef" +dependencies = [ + "alloy-primitives", + "alloy-sol-type-parser", + "serde", + "serde_json", +] + +[[package]] +name = "alloy-json-rpc" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d484c2a934d0a4d86f8ad4db8113cb1d607707a6c54f6e78f4f1b4451b47aa70" +dependencies = [ + "alloy-primitives", + "serde", + "serde_json", + "thiserror", + "tracing", +] + +[[package]] +name = "alloy-network" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a20eba9bc551037f0626d6d29e191888638d979943fa4e842e9e6fc72bf0565" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-json-rpc", + "alloy-primitives", + "alloy-rpc-types-eth", + "alloy-serde", + "alloy-signer", + "alloy-sol-types", + "async-trait", + "auto_impl", + "futures-utils-wasm", + "thiserror", +] + +[[package]] +name = "alloy-primitives" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f783611babedbbe90db3478c120fb5f5daacceffc210b39adc0af4fe0da70bad" +dependencies = [ + "alloy-rlp", + "arbitrary", + "bytes", + "cfg-if 1.0.0", + "const-hex", + "derive_arbitrary", + "derive_more", + "ethereum_ssz", + "getrandom", + "hex-literal", + "itoa", + "k256", + "keccak-asm", + "proptest", + "proptest-derive", + "rand", + "ruint", + "serde", + "tiny-keccak", +] + +[[package]] +name = "alloy-provider" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad5d89acb7339fad13bc69e7b925232f242835bfd91c82fcb9326b36481bd0f0" +dependencies = [ + "alloy-chains", + "alloy-consensus", + "alloy-eips", + "alloy-json-rpc", + "alloy-network", + "alloy-primitives", + "alloy-rpc-client", + "alloy-rpc-types-eth", + "alloy-transport", + "alloy-transport-http", + "async-stream", + "async-trait", + "auto_impl", + "dashmap", + "futures", + "futures-utils-wasm", + "lru", + "pin-project", + "reqwest", + "serde", + "serde_json", + "tokio", + "tracing", + "url", +] + +[[package]] +name = "alloy-rlp" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a43b18702501396fa9bcdeecd533bc85fac75150d308fc0f6800a01e6234a003" +dependencies = [ + "alloy-rlp-derive", + "arrayvec", + "bytes", +] + +[[package]] +name = "alloy-rlp-derive" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d83524c1f6162fcb5b0decf775498a125066c86dda6066ed609531b0e912f85a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.68", +] + +[[package]] +name = "alloy-rpc-client" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ce003e8c74bbbc7d4235131c1d6b7eaf14a533ae850295b90d240340989cb" +dependencies = [ + "alloy-json-rpc", + "alloy-transport", + "alloy-transport-http", + "futures", + "pin-project", + "reqwest", + "serde", + "serde_json", + "tokio", + "tokio-stream", + "tower", + "tracing", + "url", +] + +[[package]] +name = "alloy-rpc-types" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dfa1dd3e0bc3a3d89744fba8d1511216e83257160da2cd028a18b7d9c026030" +dependencies = [ + "alloy-rpc-types-eth", + "alloy-serde", +] + +[[package]] +name = "alloy-rpc-types-eth" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13bd7aa9ff9e67f1ba7ee0dd8cebfc95831d1649b0e4eeefae940dc3681079fa" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-primitives", + "alloy-rlp", + "alloy-serde", + "alloy-sol-types", + "itertools 0.13.0", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "alloy-serde" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8913f9e825068d77c516188c221c44f78fd814fce8effe550a783295a2757d19" +dependencies = [ + "alloy-primitives", + "serde", + "serde_json", +] + +[[package]] +name = "alloy-signer" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f740e13eb4c6a0e4d0e49738f1e86f31ad2d7ef93be499539f492805000f7237" +dependencies = [ + "alloy-primitives", + "async-trait", + "auto_impl", + "elliptic-curve", + "k256", + "thiserror", +] + +[[package]] +name = "alloy-signer-local" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87db68d926887393a1d0f9c43833b44446ea29d603291e7b20e5d115f31aa4e3" +dependencies = [ + "alloy-consensus", + "alloy-network", + "alloy-primitives", + "alloy-signer", + "async-trait", + "elliptic-curve", + "eth-keystore", + "k256", + "rand", + "thiserror", +] + +[[package]] +name = "alloy-sol-macro" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bad41a7c19498e3f6079f7744656328699f8ea3e783bdd10d85788cd439f572" +dependencies = [ + "alloy-sol-macro-expander", + "alloy-sol-macro-input", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.68", +] + +[[package]] +name = "alloy-sol-macro-expander" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd9899da7d011b4fe4c406a524ed3e3f963797dbc93b45479d60341d3a27b252" +dependencies = [ + "alloy-json-abi", + "alloy-sol-macro-input", + "const-hex", + "heck", + "indexmap 2.2.6", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.68", + "syn-solidity", + "tiny-keccak", +] + +[[package]] +name = "alloy-sol-macro-input" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d32d595768fdc61331a132b6f65db41afae41b9b97d36c21eb1b955c422a7e60" +dependencies = [ + "alloy-json-abi", + "const-hex", + "dunce", + "heck", + "proc-macro2", + "quote", + "serde_json", + "syn 2.0.68", + "syn-solidity", +] + +[[package]] +name = "alloy-sol-type-parser" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baa2fbd22d353d8685bd9fee11ba2d8b5c3b1d11e56adb3265fcf1f32bfdf404" +dependencies = [ + "winnow 0.6.13", +] + +[[package]] +name = "alloy-sol-types" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a49042c6d3b66a9fe6b2b5a8bf0d39fc2ae1ee0310a2a26ffedd79fb097878dd" +dependencies = [ + "alloy-json-abi", + "alloy-primitives", + "alloy-sol-macro", + "const-hex", + "serde", +] + +[[package]] +name = "alloy-transport" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd9773e4ec6832346171605c776315544bd06e40f803e7b5b7824b325d5442ca" +dependencies = [ + "alloy-json-rpc", + "base64", + "futures-util", + "futures-utils-wasm", + "serde", + "serde_json", + "thiserror", + "tokio", + "tower", + "url", +] + +[[package]] +name = "alloy-transport-http" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff8ef947b901c0d4e97370f9fa25844cf8b63b1a58fd4011ee82342dc8a9fc6b" +dependencies = [ + "alloy-json-rpc", + "alloy-transport", + "reqwest", + "serde_json", + "tower", + "tracing", + "url", +] + +[[package]] +name = "anstream" +version = "0.6.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" + +[[package]] +name = "anstyle-parse" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + +[[package]] +name = "arbitrary" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" + +[[package]] +name = "ark-ff" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b3235cc41ee7a12aaaf2c575a2ad7b46713a8a50bda2fc3b003a04845c05dd6" +dependencies = [ + "ark-ff-asm 0.3.0", + "ark-ff-macros 0.3.0", + "ark-serialize 0.3.0", + "ark-std 0.3.0", + "derivative", + "num-bigint", + "num-traits", + "paste", + "rustc_version 0.3.3", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +dependencies = [ + "ark-ff-asm 0.4.2", + "ark-ff-macros 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", + "derivative", + "digest 0.10.7", + "itertools 0.10.5", + "num-bigint", + "num-traits", + "paste", + "rustc_version 0.4.0", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db02d390bf6643fb404d3d22d31aee1c4bc4459600aef9113833d17e786c6e44" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-asm" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fd794a08ccb318058009eefdf15bcaaaaf6f8161eb3345f907222bac38b20" +dependencies = [ + "num-bigint", + "num-traits", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-serialize" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6c2b318ee6e10f8c2853e73a83adc0ccb88995aa978d8a3408d492ab2ee671" +dependencies = [ + "ark-std 0.3.0", + "digest 0.9.0", +] + +[[package]] +name = "ark-serialize" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +dependencies = [ + "ark-std 0.4.0", + "digest 0.10.7", + "num-bigint", +] + +[[package]] +name = "ark-std" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c" +dependencies = [ + "num-traits", + "rand", +] + +[[package]] +name = "ark-std" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand", +] + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "async-stream" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.68", +] + +[[package]] +name = "async-trait" +version = "0.1.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.68", +] + +[[package]] +name = "auto_impl" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.68", +] + +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "backtrace" +version = "0.3.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +dependencies = [ + "addr2line", + "cc", + "cfg-if 1.0.0", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "benches" +version = "0.1.0" +dependencies = [ + "alloy", + "alloy-primitives", + "alloy-sol-types", + "e2e", + "eyre", + "futures", + "keccak-const", + "koba", + "pyth-stylus", + "serde", + "stylus-sdk", + "tokio", +] + +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "blst" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62dc83a094a71d43eeadd254b1ec2d24cb6a0bb6cadce00df51f0db594711a32" +dependencies = [ + "cc", + "glob", + "threadpool", + "zeroize", +] + +[[package]] +name = "brotli-sys" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4445dea95f4c2b41cde57cc9fee236ae4dbae88d8fcbdb4750fc1bb5d86aaecd" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "brotli2" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cb036c3eade309815c15ddbacec5b22c4d1f3983a774ab2eac2e3e9ea85568e" +dependencies = [ + "brotli-sys", + "libc", +] + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[package]] +name = "byte-slice-cast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" + +[[package]] +name = "bytecheck" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23cdc57ce23ac53c931e88a43d06d070a6fd142f2617be5855eb75efc9beb1c2" +dependencies = [ + "bytecheck_derive", + "ptr_meta", + "simdutf8", +] + +[[package]] +name = "bytecheck_derive" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db406d29fbcd95542e92559bed4d8ad92636d1ca8b3b72ede10b4bcc010e659" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" +dependencies = [ + "serde", +] + +[[package]] +name = "bytesize" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e368af43e418a04d52505cf3dbc23dda4e3407ae2fa99fd0e4f308ce546acc" + +[[package]] +name = "c-kzg" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdf100c4cea8f207e883ff91ca886d621d8a166cb04971dfaa9bb8fd99ed95df" +dependencies = [ + "blst", + "cc", + "glob", + "hex", + "libc", + "serde", +] + +[[package]] +name = "cc" +version = "1.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74b6a57f98764a267ff415d50a25e6e166f3831a5071af4995296ea97d210490" + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + +[[package]] +name = "clap" +version = "4.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84b3edb18336f4df585bc9aa31dd99c036dfa5dc5e9a2939a722a188f3a8970d" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1c09dd5ada6c6c78075d6fd0da3f90d8080651e2d6cc8eb2f1aaa4034ced708" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bac35c6dafb060fd4d275d9a4ffae97917c13a6327903a8be2153cd964f7085" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.68", +] + +[[package]] +name = "clap_lex" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" + +[[package]] +name = "colorchoice" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" + +[[package]] +name = "const-hex" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8a24a26d37e1ffd45343323dc9fe6654ceea44c12f2fcb3d7ac29e610bc6" +dependencies = [ + "cfg-if 1.0.0", + "cpufeatures", + "hex", + "proptest", + "serde", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "convert_case" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" + +[[package]] +name = "corosensei" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80128832c58ea9cbd041d2a759ec449224487b2c1e400453d99d244eead87a8e" +dependencies = [ + "autocfg", + "cfg-if 1.0.0", + "libc", + "scopeguard", + "windows-sys 0.33.0", +] + +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[package]] +name = "cranelift-bforest" +version = "0.91.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2ab4512dfd3a6f4be184403a195f76e81a8a9f9e6c898e19d2dc3ce20e0115" +dependencies = [ + "cranelift-entity", +] + +[[package]] +name = "cranelift-codegen" +version = "0.91.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98b022ed2a5913a38839dfbafe6cf135342661293b08049843362df4301261dc" +dependencies = [ + "arrayvec", + "bumpalo", + "cranelift-bforest", + "cranelift-codegen-meta", + "cranelift-codegen-shared", + "cranelift-egraph", + "cranelift-entity", + "cranelift-isle", + "gimli 0.26.2", + "log", + "regalloc2", + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cranelift-codegen-meta" +version = "0.91.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "639307b45434ad112a98f8300c0f0ab085cbefcd767efcdef9ef19d4c0756e74" +dependencies = [ + "cranelift-codegen-shared", +] + +[[package]] +name = "cranelift-codegen-shared" +version = "0.91.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "278e52e29c53fcf32431ef08406c295699a70306d05a0715c5b1bf50e33a9ab7" + +[[package]] +name = "cranelift-egraph" +version = "0.91.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624b54323b06e675293939311943ba82d323bb340468ce1889be5da7932c8d73" +dependencies = [ + "cranelift-entity", + "fxhash", + "hashbrown 0.12.3", + "indexmap 1.9.3", + "log", + "smallvec", +] + +[[package]] +name = "cranelift-entity" +version = "0.91.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a59bcbca89c3f1b70b93ab3cbba5e5e0cbf3e63dadb23c7525cb142e21a9d4c" + +[[package]] +name = "cranelift-frontend" +version = "0.91.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d70abacb8cfef3dc8ff7e8836e9c1d70f7967dfdac824a4cd5e30223415aca6" +dependencies = [ + "cranelift-codegen", + "log", + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cranelift-isle" +version = "0.91.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "393bc73c451830ff8dbb3a07f61843d6cb41a084f9996319917c0b291ed785bb" + +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher", +] + +[[package]] +name = "darling" +version = "0.20.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83b2eb4d90d12bdda5ed17de686c2acb4c57914f8f921b8da7e112b5a36f3fe1" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622687fe0bac72a04e5599029151f5796111b90f1baaa9b544d807a5e31cd120" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "syn 2.0.68", +] + +[[package]] +name = "darling_macro" +version = "0.20.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "733cabb43482b1a1b53eee8583c2b9e8684d592215ea83efd305dd31bc2f0178" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.68", +] + +[[package]] +name = "dashmap" +version = "5.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +dependencies = [ + "cfg-if 1.0.0", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", +] + +[[package]] +name = "der" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_arbitrary" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.68", +] + +[[package]] +name = "derive_more" +version = "0.99.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" +dependencies = [ + "convert_case 0.4.0", + "proc-macro2", + "quote", + "rustc_version 0.4.0", + "syn 2.0.68", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "dunce" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" + +[[package]] +name = "e2e" +version = "0.1.0" +source = "git+https://github.com/Ifechukwudaniel/e2e-stylus#bbcc5885f0b45a53d1f87adcbf31c0b5e7e144d2" +dependencies = [ + "alloy", + "e2e-proc", + "eyre", + "koba", + "once_cell", + "regex", + "tokio", + "toml", +] + +[[package]] +name = "e2e-proc" +version = "0.1.0" +source = "git+https://github.com/Ifechukwudaniel/e2e-proc-stylus#6894e8b62896ed16fb3128664ec2f390536c27c5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.68", +] + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest 0.10.7", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest 0.10.7", + "ff", + "generic-array", + "group", + "pkcs8", + "rand_core", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "enum-iterator" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eeac5c5edb79e4e39fe8439ef35207780a11f69c52cbe424ce3dfad4cb78de6" +dependencies = [ + "enum-iterator-derive", +] + +[[package]] +name = "enum-iterator-derive" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c134c37760b27a871ba422106eedbb8247da973a09e82558bf26d619c882b159" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "enumset" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "226c0da7462c13fb57e5cc9e0dc8f0635e7d27f276a3a7fd30054647f669007d" +dependencies = [ + "enumset_derive", +] + +[[package]] +name = "enumset_derive" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08b6c6ab82d70f08844964ba10c7babb716de2ecaeab9be5717918a5177d3af" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.68", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "eth-keystore" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fda3bf123be441da5260717e0661c25a2fd9cb2b2c1d20bf2e05580047158ab" +dependencies = [ + "aes", + "ctr", + "digest 0.10.7", + "hex", + "hmac", + "pbkdf2", + "rand", + "scrypt", + "serde", + "serde_json", + "sha2", + "sha3", + "thiserror", + "uuid 0.8.2", +] + +[[package]] +name = "ethbloom" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" +dependencies = [ + "crunchy", + "fixed-hash", + "impl-rlp", + "impl-serde", + "tiny-keccak", +] + +[[package]] +name = "ethereum-types" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" +dependencies = [ + "ethbloom", + "fixed-hash", + "impl-rlp", + "impl-serde", + "primitive-types", + "uint", +] + +[[package]] +name = "ethereum_ssz" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d3627f83d8b87b432a5fad9934b4565260722a141a2c40f371f8080adec9425" +dependencies = [ + "ethereum-types", + "itertools 0.10.5", + "smallvec", +] + +[[package]] +name = "eyre" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" +dependencies = [ + "indenter", + "once_cell", +] + +[[package]] +name = "fallible-iterator" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" + +[[package]] +name = "fastrand" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" + +[[package]] +name = "fastrlp" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139834ddba373bbdd213dffe02c8d110508dcf1726c2be27e8d1f7d7e1856418" +dependencies = [ + "arrayvec", + "auto_impl", + "bytes", +] + +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "rand_core", + "subtle", +] + +[[package]] +name = "fixed-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" +dependencies = [ + "arbitrary", + "byteorder", + "rand", + "rustc-hex", + "static_assertions", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "function-calls-example" +version = "0.1.0" +dependencies = [ + "alloy", + "alloy-primitives", + "alloy-sol-types", + "e2e", + "eyre", + "keccak-const", + "mini-alloc", + "pyth-stylus", + "stylus-sdk", + "tokio", +] + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futures" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-executor" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" + +[[package]] +name = "futures-macro" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.68", +] + +[[package]] +name = "futures-sink" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" + +[[package]] +name = "futures-task" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" + +[[package]] +name = "futures-util" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "futures-utils-wasm" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42012b0f064e01aa58b545fe3727f90f7dd4020f4a3ea735b50344965f5a57e9" + +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "wasi", +] + +[[package]] +name = "gimli" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d" +dependencies = [ + "fallible-iterator", + "indexmap 1.9.3", + "stable_deref_trait", +] + +[[package]] +name = "gimli" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core", + "subtle", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash 0.7.8", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash 0.8.11", + "allocator-api2", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +dependencies = [ + "serde", +] + +[[package]] +name = "hex-literal" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "http" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +dependencies = [ + "bytes", + "futures-util", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" + +[[package]] +name = "hyper" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe575dd17d0862a9a33781c8c4696a55c320909004a67a00fb286ba8b1bc496d" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "httparse", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-tls" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" +dependencies = [ + "bytes", + "http-body-util", + "hyper", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b875924a60b96e5d7b9ae7b066540b1dd1cbd90d1828f54c92e02a283351c56" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "hyper", + "pin-project-lite", + "socket2", + "tokio", + "tower", + "tower-service", + "tracing", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "impl-codec" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" +dependencies = [ + "parity-scale-codec", +] + +[[package]] +name = "impl-rlp" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808" +dependencies = [ + "rlp", +] + +[[package]] +name = "impl-serde" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc88fc67028ae3db0c853baa36269d398d5f45b6982f95549ff5def78c935cd" +dependencies = [ + "serde", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "indenter" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", +] + +[[package]] +name = "indexmap" +version = "2.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +dependencies = [ + "equivalent", + "hashbrown 0.14.5", +] + +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + +[[package]] +name = "ipnet" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "js-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "k256" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b" +dependencies = [ + "cfg-if 1.0.0", + "ecdsa", + "elliptic-curve", + "once_cell", + "sha2", +] + +[[package]] +name = "keccak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "keccak-asm" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47a3633291834c4fbebf8673acbc1b04ec9d151418ff9b8e26dcd79129928758" +dependencies = [ + "digest 0.10.7", + "sha3-asm", +] + +[[package]] +name = "keccak-const" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57d8d8ce877200136358e0bbff3a77965875db3af755a11e1fa6b1b3e2df13ea" + +[[package]] +name = "koba" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80e92e1148d087df999396266311bece9e5311c352821872cccaf5dc67117cfc" +dependencies = [ + "alloy", + "brotli2", + "bytesize", + "clap", + "eyre", + "hex", + "once_cell", + "owo-colors", + "regex", + "tempfile", + "tokio", + "wasmer", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "leb128" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" + +[[package]] +name = "libc" +version = "0.2.155" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" + +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "lru" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3262e75e648fce39813cb56ac41f3c3e3f65217ebf3844d818d1f9398cfb0dc" +dependencies = [ + "hashbrown 0.14.5", +] + +[[package]] +name = "mach" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" +dependencies = [ + "libc", +] + +[[package]] +name = "mach2" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b955cdeb2a02b9117f121ce63aa52d08ade45de53e48fe6a38b39c10f6f709" +dependencies = [ + "libc", +] + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "memmap2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" +dependencies = [ + "libc", +] + +[[package]] +name = "memoffset" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" +dependencies = [ + "autocfg", +] + +[[package]] +name = "memory_units" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8452105ba047068f40ff7093dd1d9da90898e63dd61736462e9cdda6a90ad3c3" + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mini-alloc" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd9993556d3850cdbd0da06a3dc81297edcfa050048952d84d75e8b944e8f5af" +dependencies = [ + "cfg-if 1.0.0", + "wee_alloc", +] + +[[package]] +name = "miniz_oxide" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.48.0", +] + +[[package]] +name = "more-asserts" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7843ec2de400bcbc6a6328c958dc38e5359da6e93e72e37bc5246bf1ae776389" + +[[package]] +name = "motsu" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "744174e5011fed86212d90c1120037da87e0c45fee7a5861c2b3105e41283810" +dependencies = [ + "const-hex", + "motsu-proc", + "once_cell", + "stylus-sdk", + "tiny-keccak", +] + +[[package]] +name = "motsu-proc" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0785317ee15f9a1bc5d761da9d0d1dadd92225cd5a88eed0ec37c54a277fac44" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.68", +] + +[[package]] +name = "native-tls" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "num_enum" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.68", +] + +[[package]] +name = "object" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "081b846d1d56ddfc18fdf1a922e4f6e07a11768ea1b92dec44e42b72712ccfce" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "openssl" +version = "0.10.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" +dependencies = [ + "bitflags 2.6.0", + "cfg-if 1.0.0", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.68", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "owo-colors" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caff54706df99d2a78a5a4e3455ff45448d81ef1bb63c22cd14052ca0e993a3f" + +[[package]] +name = "parity-scale-codec" +version = "3.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" +dependencies = [ + "arrayvec", + "bitvec", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "serde", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.52.5", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pest" +version = "2.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "560131c633294438da9f7c4b08189194b20946c8274c6b9e38881a7874dc8ee8" +dependencies = [ + "memchr", + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pin-project" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.68", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "pkg-config" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "primitive-types" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" +dependencies = [ + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde", + "uint", +] + +[[package]] +name = "proc-macro-crate" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +dependencies = [ + "toml_edit 0.21.1", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "proptest" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4c2511913b88df1637da85cc8d96ec8e43a3f8bb8ccb71ee1ac240d6f3df58d" +dependencies = [ + "bit-set", + "bit-vec", + "bitflags 2.6.0", + "lazy_static", + "num-traits", + "rand", + "rand_chacha", + "rand_xorshift", + "regex-syntax", + "rusty-fork", + "tempfile", + "unarray", +] + +[[package]] +name = "proptest-derive" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf16337405ca084e9c78985114633b6827711d22b9e6ef6c6c0d665eb3f0b6e" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "proxy-calls-example" +version = "0.1.0" +dependencies = [ + "alloy", + "alloy-primitives", + "alloy-sol-types", + "e2e", + "eyre", + "keccak-const", + "mini-alloc", + "pyth-stylus", + "stylus-sdk", + "tokio", +] + +[[package]] +name = "ptr_meta" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" +dependencies = [ + "ptr_meta_derive", +] + +[[package]] +name = "ptr_meta_derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "pyth-stylus" +version = "0.1.0" +dependencies = [ + "alloy-primitives", + "alloy-sol-macro", + "alloy-sol-macro-expander", + "alloy-sol-macro-input", + "alloy-sol-types", + "keccak-const", + "mini-alloc", + "motsu", + "stylus-sdk", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_xorshift" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +dependencies = [ + "rand_core", +] + +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "redox_syscall" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd" +dependencies = [ + "bitflags 2.6.0", +] + +[[package]] +name = "regalloc2" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "300d4fbfb40c1c66a78ba3ddd41c1110247cf52f97b87d0f2fc9209bd49b030c" +dependencies = [ + "fxhash", + "log", + "slice-group-by", + "smallvec", +] + +[[package]] +name = "regex" +version = "1.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" + +[[package]] +name = "region" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6b6ebd13bc009aef9cd476c1310d49ac354d36e240cf1bd753290f3dc7199a7" +dependencies = [ + "bitflags 1.3.2", + "libc", + "mach2", + "windows-sys 0.52.0", +] + +[[package]] +name = "rend" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71fe3824f5629716b1589be05dacd749f6aa084c87e00e016714a8cdfccc997c" +dependencies = [ + "bytecheck", +] + +[[package]] +name = "reqwest" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7d6d2a27d57148378eb5e111173f4276ad26340ecc5c49a4a2152167a2d6a37" +dependencies = [ + "base64", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-tls", + "hyper-util", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls-pemfile", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-native-tls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "rkyv" +version = "0.7.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cba464629b3394fc4dbc6f940ff8f5b4ff5c7aef40f29166fd4ad12acbc99c0" +dependencies = [ + "bitvec", + "bytecheck", + "bytes", + "hashbrown 0.12.3", + "indexmap 1.9.3", + "ptr_meta", + "rend", + "rkyv_derive", + "seahash", + "tinyvec", + "uuid 1.9.1", +] + +[[package]] +name = "rkyv_derive" +version = "0.7.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7dddfff8de25e6f62b9d64e6e432bf1c6736c57d20323e15ee10435fbda7c65" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "rlp" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" +dependencies = [ + "bytes", + "rustc-hex", +] + +[[package]] +name = "ruint" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c3cc4c2511671f327125da14133d0c5c5d137f006a1017a16f557bc85b16286" +dependencies = [ + "alloy-rlp", + "arbitrary", + "ark-ff 0.3.0", + "ark-ff 0.4.2", + "bytes", + "fastrlp", + "num-bigint", + "num-traits", + "parity-scale-codec", + "primitive-types", + "proptest", + "rand", + "rlp", + "ruint-macro", + "serde", + "valuable", + "zeroize", +] + +[[package]] +name = "ruint-macro" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48fd7bd8a6377e15ad9d42a8ec25371b94ddc67abe7c8b9127bec79bebaaae18" + +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "rustc-hex" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" + +[[package]] +name = "rustc_version" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" +dependencies = [ + "semver 0.11.0", +] + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver 1.0.23", +] + +[[package]] +name = "rustix" +version = "0.38.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +dependencies = [ + "bitflags 2.6.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustls-pemfile" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" +dependencies = [ + "base64", + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" + +[[package]] +name = "rustversion" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" + +[[package]] +name = "rusty-fork" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" +dependencies = [ + "fnv", + "quick-error", + "tempfile", + "wait-timeout", +] + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "salsa20" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" +dependencies = [ + "cipher", +] + +[[package]] +name = "schannel" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "scrypt" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f9e24d2b632954ded8ab2ef9fea0a0c769ea56ea98bddbafbad22caeeadf45d" +dependencies = [ + "hmac", + "pbkdf2", + "salsa20", + "sha2", +] + +[[package]] +name = "seahash" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "security-framework" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0" +dependencies = [ + "bitflags 2.6.0", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "317936bbbd05227752583946b9e66d7ce3b489f84e11a94a510b4437fef407d7" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" + +[[package]] +name = "semver-parser" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" +dependencies = [ + "pest", +] + +[[package]] +name = "serde" +version = "1.0.203" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde-wasm-bindgen" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3b4c031cd0d9014307d82b8abf653c0290fbdaeb4c02d00c63cf52f728628bf" +dependencies = [ + "js-sys", + "serde", + "wasm-bindgen", +] + +[[package]] +name = "serde_derive" +version = "1.0.203" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.68", +] + +[[package]] +name = "serde_json" +version = "1.0.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8eddb61f0697cc3989c5d64b452f5488e2b8a60fd7d5076a3045076ffef8cb0" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_spanned" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if 1.0.0", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest 0.10.7", + "keccak", +] + +[[package]] +name = "sha3-asm" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9b57fd861253bff08bb1919e995f90ba8f4889de2726091c8876f3a4e823b40" +dependencies = [ + "cc", + "cfg-if 1.0.0", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +dependencies = [ + "libc", +] + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest 0.10.7", + "rand_core", +] + +[[package]] +name = "simdutf8" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a" + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "slice-group-by" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "826167069c09b99d56f31e9ae5c99049e932a98c9dc2dac47645b08dbbf76ba7" + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "socket2" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "strum" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.68", +] + +[[package]] +name = "stylus-proc" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fd02e91dffe7b73df84a861c992494d6b72054bc9a17fe73e147e34e9a64ef3" +dependencies = [ + "alloy-primitives", + "alloy-sol-types", + "cfg-if 1.0.0", + "convert_case 0.6.0", + "lazy_static", + "proc-macro2", + "quote", + "regex", + "sha3", + "syn 1.0.109", + "syn-solidity", +] + +[[package]] +name = "stylus-sdk" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26042693706e29fb7e3cf3d71c99534ac97fca98b6f81ba77ab658022ab2e210" +dependencies = [ + "alloy-primitives", + "alloy-sol-types", + "cfg-if 1.0.0", + "derivative", + "hex", + "keccak-const", + "lazy_static", + "stylus-proc", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "901fa70d88b9d6c98022e23b4136f9f3e54e4662c3bc1bd1d84a42a9a0f0c1e9" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn-solidity" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d71e19bca02c807c9faa67b5a47673ff231b6e7449b251695188522f1dc44b2" +dependencies = [ + "paste", + "proc-macro2", + "quote", + "syn 2.0.68", +] + +[[package]] +name = "sync_wrapper" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "target-lexicon" +version = "0.12.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1fc403891a21bcfb7c37834ba66a547a8f402146eba7265b5a6d88059c9ff2f" + +[[package]] +name = "tempfile" +version = "3.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +dependencies = [ + "cfg-if 1.0.0", + "fastrand", + "rustix", + "windows-sys 0.52.0", +] + +[[package]] +name = "thiserror" +version = "1.0.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.68", +] + +[[package]] +name = "threadpool" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" +dependencies = [ + "num_cpus", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "tinyvec" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c55115c6fbe2d2bef26eb09ad74bde02d8255476fc0c7b515ef09fbb35742d82" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "num_cpus", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.48.0", +] + +[[package]] +name = "tokio-macros" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.68", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-stream" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", + "tokio-util", +] + +[[package]] +name = "tokio-util" +version = "0.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml" +version = "0.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f49eb2ab21d2f26bd6db7bf383edc527a7ebaee412d17af4d40fdccd442f335" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit 0.22.14", +] + +[[package]] +name = "toml_datetime" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +dependencies = [ + "indexmap 2.2.6", + "toml_datetime", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.22.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f21c7aaf97f1bd9ca9d4f9e73b0a6c74bd5afef56f2bc931943a6e1c37e04e38" +dependencies = [ + "indexmap 2.2.6", + "serde", + "serde_spanned", + "toml_datetime", + "winnow 0.6.13", +] + +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", + "tokio", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.68", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "ucd-trie" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" + +[[package]] +name = "uint" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" +dependencies = [ + "arbitrary", + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + +[[package]] +name = "unicode-bidi" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-normalization" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-segmentation" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" + +[[package]] +name = "unicode-width" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" + +[[package]] +name = "url" +version = "2.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "uuid" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" +dependencies = [ + "getrandom", + "serde", +] + +[[package]] +name = "uuid" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5de17fd2f7da591098415cff336e12965a28061ddace43b59cb3c430179c9439" + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wait-timeout" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" +dependencies = [ + "libc", +] + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +dependencies = [ + "cfg-if 1.0.0", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.68", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-downcast" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dac026d43bcca6e7ce1c0956ba68f59edf6403e8e930a5d891be72c31a44340" +dependencies = [ + "js-sys", + "once_cell", + "wasm-bindgen", + "wasm-bindgen-downcast-macros", +] + +[[package]] +name = "wasm-bindgen-downcast-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5020cfa87c7cecefef118055d44e3c1fc122c7ec25701d528ee458a0b45f38f" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +dependencies = [ + "cfg-if 1.0.0", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.68", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" + +[[package]] +name = "wasm-encoder" +version = "0.212.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "501940df4418b8929eb6d52f1aade1fdd15a5b86c92453cb696e3c906bd3fc33" +dependencies = [ + "leb128", +] + +[[package]] +name = "wasmer" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78caedecd8cb71ed47ccca03b68d69414a3d278bb031e6f93f15759344efdd52" +dependencies = [ + "bytes", + "cfg-if 1.0.0", + "derivative", + "indexmap 1.9.3", + "js-sys", + "more-asserts", + "rustc-demangle", + "serde", + "serde-wasm-bindgen", + "target-lexicon", + "thiserror", + "wasm-bindgen", + "wasm-bindgen-downcast", + "wasmer-compiler", + "wasmer-compiler-cranelift", + "wasmer-derive", + "wasmer-types", + "wasmer-vm", + "wat", + "winapi", +] + +[[package]] +name = "wasmer-compiler" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "726a8450541af4a57c34af7b6973fdbfc79f896cc7e733429577dfd1d1687180" +dependencies = [ + "backtrace", + "cfg-if 1.0.0", + "enum-iterator", + "enumset", + "lazy_static", + "leb128", + "memmap2", + "more-asserts", + "region", + "smallvec", + "thiserror", + "wasmer-types", + "wasmer-vm", + "wasmparser", + "winapi", +] + +[[package]] +name = "wasmer-compiler-cranelift" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1e5633f90f372563ebbdf3f9799c7b29ba11c90e56cf9b54017112d2e656c95" +dependencies = [ + "cranelift-codegen", + "cranelift-entity", + "cranelift-frontend", + "gimli 0.26.2", + "more-asserts", + "rayon", + "smallvec", + "target-lexicon", + "tracing", + "wasmer-compiler", + "wasmer-types", +] + +[[package]] +name = "wasmer-derive" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97901fdbaae383dbb90ea162cc3a76a9fa58ac39aec7948b4c0b9bbef9307738" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "wasmer-types" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67f1f2839f4f61509550e4ddcd0e658e19f3af862b51c79fda15549d735d659b" +dependencies = [ + "bytecheck", + "enum-iterator", + "enumset", + "indexmap 1.9.3", + "more-asserts", + "rkyv", + "target-lexicon", + "thiserror", +] + +[[package]] +name = "wasmer-vm" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "043118ec4f16d1714fed3aab758b502b864bd865e1d5188626c9ad290100563f" +dependencies = [ + "backtrace", + "cc", + "cfg-if 1.0.0", + "corosensei", + "dashmap", + "derivative", + "enum-iterator", + "fnv", + "indexmap 1.9.3", + "lazy_static", + "libc", + "mach", + "memoffset", + "more-asserts", + "region", + "scopeguard", + "thiserror", + "wasmer-types", + "winapi", +] + +[[package]] +name = "wasmparser" +version = "0.95.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2ea896273ea99b15132414be1da01ab0d8836415083298ecaffbe308eaac87a" +dependencies = [ + "indexmap 1.9.3", + "url", +] + +[[package]] +name = "wast" +version = "212.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4606a05fb0aae5d11dd7d8280a640d88a63ee019360ba9be552da3d294b8d1f5" +dependencies = [ + "bumpalo", + "leb128", + "memchr", + "unicode-width", + "wasm-encoder", +] + +[[package]] +name = "wat" +version = "1.212.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c74ca7f93f11a5d6eed8499f2a8daaad6e225cab0151bc25a091fff3b987532f" +dependencies = [ + "wast", +] + +[[package]] +name = "web-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "wee_alloc" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbb3b5a6b2bb17cb6ad44a2e68a43e8d2722c997da10e928665c72ec6c0a0b8e" +dependencies = [ + "cfg-if 0.1.10", + "libc", + "memory_units", + "winapi", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43dbb096663629518eb1dfa72d80243ca5a6aca764cae62a2df70af760a9be75" +dependencies = [ + "windows_aarch64_msvc 0.33.0", + "windows_i686_gnu 0.33.0", + "windows_i686_msvc 0.33.0", + "windows_x86_64_gnu 0.33.0", + "windows_x86_64_msvc 0.33.0", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.5", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +dependencies = [ + "windows_aarch64_gnullvm 0.52.5", + "windows_aarch64_msvc 0.52.5", + "windows_i686_gnu 0.52.5", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.5", + "windows_x86_64_gnu 0.52.5", + "windows_x86_64_gnullvm 0.52.5", + "windows_x86_64_msvc 0.52.5", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd761fd3eb9ab8cc1ed81e56e567f02dd82c4c837e48ac3b2181b9ffc5060807" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" + +[[package]] +name = "windows_i686_gnu" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab0cf703a96bab2dc0c02c0fa748491294bf9b7feb27e1f4f96340f208ada0e" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" + +[[package]] +name = "windows_i686_msvc" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cfdbe89cc9ad7ce618ba34abc34bbb6c36d99e96cae2245b7943cd75ee773d0" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4dd9b0c0e9ece7bb22e84d70d01b71c6d6248b81a3c60d11869451b4cb24784" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff1e4aa646495048ec7f3ffddc411e1d829c026a2ec62b39da15c1055e406eaa" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" + +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + +[[package]] +name = "winnow" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59b5e5f6c299a3c7890b876a2a587f3115162487e704907d9b6cd29473052ba1" +dependencies = [ + "memchr", +] + +[[package]] +name = "winreg" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" +dependencies = [ + "cfg-if 1.0.0", + "windows-sys 0.48.0", +] + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "zerocopy" +version = "0.7.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.68", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.68", +] diff --git a/target_chains/ethereum/sdk/stylus/Cargo.toml b/target_chains/ethereum/sdk/stylus/Cargo.toml new file mode 100644 index 0000000000..6bd6741c50 --- /dev/null +++ b/target_chains/ethereum/sdk/stylus/Cargo.toml @@ -0,0 +1,90 @@ +[workspace] +members = [ + "contracts", + "examples/function-calls", + "examples/proxy-calls", + "benches" +] +default-members = [ + "contracts", + "examples/function-calls", + "examples/proxy-calls", +] + +# Explicitly set the resolver to version 2, which is the default for packages +# with edition >= 2021. +# https://doc.rust-lang.org/edition-guide/rust-2021/default-cargo-resolver.html +resolver = "2" + +[workspace.package] +authors = ["Ifechukwu Daniel"] +edition = "2021" +license = "Apache-2.0" +repository = "https://github.com/pyth-network/pyth-crosschain" +version = "0.1.0" + +[workspace.lints.rust] +missing_docs = "warn" +unreachable_pub = "warn" +rust_2021_compatibility = { level = "warn", priority = -1 } + + +[workspace.dependencies] +# stylus-related +stylus-sdk = { version = "0.6.0", default-features = false } +mini-alloc = "0.4.2" + +alloy = { version = "0.1.4", features = [ + "contract", + "network", + "providers", + "provider-http", + "rpc-client", + "rpc-types-eth", + "signer-local", + "getrandom", +] } +# Even though `alloy` includes `alloy-primitives` and `alloy-sol-types` we need +# to keep both versions for compatibility with the Stylus SDK. Once they start +# using `alloy` we can remove these. +alloy-primitives = { version = "0.7.6", default-features = false } +alloy-sol-types = { version = "0.7.6", default-features = false } +alloy-sol-macro = { version = "0.7.6", default-features = false } +alloy-sol-macro-expander = { version = "0.7.6", default-features = false } +alloy-sol-macro-input = { version = "0.7.6", default-features = false } + +dotenv = "0.15.0" +const-hex = { version = "1.11.1", default-features = false } +eyre = "0.6.8" +keccak-const = "0.2.0" +koba = "0.2.0" +once_cell = "1.19.0" +rand = "0.8.5" +regex = "1.10.4" +tiny-keccak = { version = "2.0.2", features = ["keccak"] } +tokio = { version = "1.12.0", features = ["full"] } +futures = "0.3.30" + +# procedural macros +syn = { version = "2.0.58", features = ["full"] } +proc-macro2 = "1.0.79" +quote = "1.0.35" + +# members +motsu = "0.1.0" +e2e = { git = "https://github.com/Ifechukwudaniel/e2e-stylus"} +pyth-stylus ={path ="contracts"} + +[profile.release] +codegen-units = 1 +panic = "abort" +opt-level = "z" +strip = true +lto = true +debug = false +rpath = false +debug-assertions = false +incremental = false + +[profile.dev] +panic = "abort" diff --git a/target_chains/ethereum/sdk/stylus/GUIDELINES.md b/target_chains/ethereum/sdk/stylus/GUIDELINES.md new file mode 100644 index 0000000000..ae118a0bb5 --- /dev/null +++ b/target_chains/ethereum/sdk/stylus/GUIDELINES.md @@ -0,0 +1,5 @@ +# Engineering Guidelines + +For best practices, coding standards, and other essential guidelines, please refer to the official [OpenZeppelin Rust Contracts Stylus Engineering Guidelines](https://github.com/OpenZeppelin/rust-contracts-stylus/blob/main/GUIDELINES.md). + +This document outlines the principles and practices for ths codebase , maintainable, and secure Rust code within the context of the Rust Contracts Stylus project. \ No newline at end of file diff --git a/target_chains/ethereum/sdk/stylus/README.md b/target_chains/ethereum/sdk/stylus/README.md new file mode 100644 index 0000000000..4d163debfb --- /dev/null +++ b/target_chains/ethereum/sdk/stylus/README.md @@ -0,0 +1,124 @@ +# Pyth Stylus SDK + +This package provides utilities for consuming prices from the [Pyth Network](https://pyth.network/) Oracle in Rust with Stylus. It also includes the [Pyth Interface ABI](./abis/IPyth.json), which can be used in your libraries to interact with the Pyth contract. + +It is **strongly recommended** to follow the [consumer best practices](https://docs.pyth.network/documentation/pythnet-price-feeds/best-practices) when consuming data from Pyth. + +## Features + +- Integrates with the [`pyth-solidity-contracts`] library for external calls to Pyth smart contracts. +- Provides first-class `no_std` support. +- Includes Solidity constructors powered by [`koba`]. +- Supports both [unit] and [integration] test affordances for thorough testing. + +## Installation + +To add the Stylus Contracts from crates.io, add the following line to your `Cargo.toml` (pinning to a specific version is recommended): + +```toml +[dependencies] +pyth-stylus = "0.1.0" +``` + +For the latest changes from the `main` branch, you can also specify a git dependency: + +```toml +[dependencies] +pyth-stylus = { git = "https://github.com/pyth-network/pyth-crosschain.git" } +``` + +## Example Usage + +To consume prices, use the functions interface. Be sure to read the function documentation to ensure safe use of price data. + +For example, to read the latest price, call [`getPriceNoOlderThan`](https://github.com/pyth-network/pyth-crosschain/blob/stylus-sdk/target_chains/ethereum/sdk/stylus/contracts/src/pyth/functions.rs) with the Price ID of the price feed you are interested in: + +```rust +use pyth_stylus::pyth::functions::get_price_no_older_than; + +sol_storage! { + #[entrypoint] + struct FunctionCallsExample { + address pyth_address; + bytes32 price_id; + StoragePrice price; + StoragePriceFeed price_feed; + StoragePrice ema_price; + StoragePriceFeed ema_price_feed; + } +} + + +impl FunctionCallsExample { + pub fn get_price_no_older_than(&mut self) -> Result<(), Vec> { + let _ = get_price_no_older_than(self, self.pyth_address.get(), self.price_id.get(), U256::from(1000))?; + Ok(()) + } +} +``` + +Alternatively, you can interact directly with the Pyth contract, which implements the IPyth functions, instead of using call functions: + +```rust +#![cfg_attr(not(test), no_std, no_main)] +extern crate alloc; + +use stylus_sdk::prelude::{entrypoint, public, sol_storage}; +use pyth_stylus::pyth::pyth_contract::PythContract; + +sol_storage! { + #[entrypoint] + struct ProxyCallsExample { + #[borrow] + PythContract pyth; + } +} + +#[public] +#[inherit(PythContract)] +impl ProxyCallsExample { +} +``` + +## Mocking Pyth + +[MockPyth](./mock.rs) is a mock contract that can be deployed locally to simulate Pyth contract behavior. To set and update price feeds, call `updatePriceFeeds` and provide an array of encoded price feeds as the argument. Encoded price feeds can be created using the `create_price_feed_update_data` function in the mock contract, which is also available in the functions module. + + +## Test Documentation + +### Running Unit Tests for `pyth-stylus` + +To run all the unit tests for the `pyth-stylus` package with all its features enabled, use the following command: + +```bash +cargo test -p pyth-stylus --all-features +``` + +This command will: +- Target the `pyth-stylus` package specifically (`-p pyth-stylus`). +- Enable **all features** defined in the package during the test run (`--all-features`). + + +### Running End-to-End Tests + +To run the end-to-end tests for `pyth-stylus`, follow these steps: + +1. Start the test node: + + ```bash + ./scripts/nitro-testnode.sh + ``` + +2. Run the end-to-end tests: + ``` + ./scripts/e2e-tests.sh + ``` + + +### Releases + +We use [Semantic Versioning](https://semver.org/) for our releases. To release a new version of this package and publish it to npm, follow these steps: + +1. Run `npm version --no-git-tag-version` to update the package version, then push your changes to GitHub. +2. Once the change is merged into `main`, create a release with the tag `v`, such as `v1.5.2`. A GitHub action will automatically publish the new version of the package to npm. diff --git a/target_chains/ethereum/sdk/stylus/benches/Cargo.toml b/target_chains/ethereum/sdk/stylus/benches/Cargo.toml new file mode 100644 index 0000000000..8bfe677975 --- /dev/null +++ b/target_chains/ethereum/sdk/stylus/benches/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "benches" +edition.workspace = true +license.workspace = true +repository.workspace = true +publish = false +version.workspace = true + +[dependencies] +pyth-stylus.workspace = true +alloy-sol-types.workspace = true +alloy-primitives = { workspace = true, features = ["tiny-keccak"] } +alloy.workspace = true +tokio.workspace = true +futures.workspace = true +stylus-sdk.workspace = true +eyre.workspace = true +koba.workspace = true +e2e.workspace = true +keccak-const.workspace = true +serde = "1.0.203" diff --git a/target_chains/ethereum/sdk/stylus/benches/src/function_calls.rs b/target_chains/ethereum/sdk/stylus/benches/src/function_calls.rs new file mode 100644 index 0000000000..d5dea12094 --- /dev/null +++ b/target_chains/ethereum/sdk/stylus/benches/src/function_calls.rs @@ -0,0 +1,98 @@ +use std::str::FromStr; + +use alloy::{ + network::{AnyNetwork, EthereumWallet}, + primitives::{Address, FixedBytes as TypeFixedBytes}, + providers::ProviderBuilder, + sol, + sol_types::{SolCall, SolConstructor}, +}; +use e2e::{env, receipt, Account}; + +use crate::{ + report::{ContractReport, FunctionReport}, + CacheOpt, +}; + +sol!( + #[sol(rpc)] + contract FunctionCall{ + function getPriceUnsafe() external returns (int64 price); + function getEmaPriceUnsafe() external returns (int64 price); + function getPriceNoOlderThan() external returns (int64 price); + function getEmaPriceNoOlderThan() external returns (int64 price); + function getUpdateFee() external returns (uint256 fee); + function getValidTimePeriod() external returns (uint256 period); + function updatePriceFeeds() external payable; + function updatePriceFeedsIfNecessary() external payable; + } +); + +sol!("../examples/function-calls/src/constructor.sol"); + +pub async fn bench() -> eyre::Result { + let reports = run_with(CacheOpt::None).await?; + let report = reports + .into_iter() + .try_fold(ContractReport::new("FunctionCalls"), ContractReport::add)?; + + let cached_reports = run_with(CacheOpt::Bid(0)).await?; + let report = cached_reports + .into_iter() + .try_fold(report, ContractReport::add_cached)?; + + Ok(report) +} + +pub async fn run_with( + cache_opt: CacheOpt, +) -> eyre::Result> { + let alice = Account::new().await?; + let alice_wallet = ProviderBuilder::new() + .network::() + .with_recommended_fillers() + .wallet(EthereumWallet::from(alice.signer.clone())) + .on_http(alice.url().parse()?); + let contract_addr = deploy(&alice, cache_opt).await?; + + let contract = FunctionCall::new(contract_addr, &alice_wallet); + let _ = receipt!(contract.getPriceUnsafe())?; + let _ = receipt!(contract.getEmaPriceUnsafe())?; + let _ = receipt!(contract.getPriceNoOlderThan())?; + let _ = receipt!(contract.getEmaPriceNoOlderThan())?; + let _ = receipt!(contract.getUpdateFee())?; + let _ = receipt!(contract.getValidTimePeriod())?; + + /// IMPORTANT: Order matters! + use FunctionCall::*; + #[rustfmt::skip] + let receipts = vec![ + (getPriceUnsafeCall::SIGNATURE, receipt!(contract.getPriceUnsafe())?), + (getEmaPriceUnsafeCall::SIGNATURE, receipt!(contract.getEmaPriceUnsafe())?), + (getPriceNoOlderThanCall::SIGNATURE, receipt!(contract.getPriceNoOlderThan())?), + (getEmaPriceNoOlderThanCall::SIGNATURE, receipt!(contract.getEmaPriceNoOlderThan())?), + (getUpdateFeeCall::SIGNATURE, receipt!(contract.getUpdateFee())?), + (getValidTimePeriodCall::SIGNATURE, receipt!(contract.getValidTimePeriod())?), + ]; + + receipts + .into_iter() + .map(FunctionReport::new) + .collect::>>() +} + +async fn deploy( + account: &Account, + cache_opt: CacheOpt, +) -> eyre::Result
{ + let pyth_addr = env("MOCK_PYTH_ADDRESS")?; + let address = Address::from_str(&pyth_addr)?; + let id = keccak_const::Keccak256::new().update(b"ETH").finalize().to_vec(); + let price_id = TypeFixedBytes::<32>::from_slice(&id); + let args = FunctionCallsExample::constructorCall { + _pythAddress: address, + _priceId: price_id, + }; + let args = alloy::hex::encode(args.abi_encode()); + crate::deploy(account, "function-calls", Some(args), cache_opt).await +} diff --git a/target_chains/ethereum/sdk/stylus/benches/src/lib.rs b/target_chains/ethereum/sdk/stylus/benches/src/lib.rs new file mode 100644 index 0000000000..7103f3d7db --- /dev/null +++ b/target_chains/ethereum/sdk/stylus/benches/src/lib.rs @@ -0,0 +1,117 @@ +use std::process::Command; + +use alloy::{ + primitives::Address, + rpc::types::{ + serde_helpers::WithOtherFields, AnyReceiptEnvelope, Log, + TransactionReceipt, + }, +}; +use alloy_primitives::U128; +use e2e::{Account, ReceiptExt}; +use eyre::WrapErr; +use koba::config::{Deploy, Generate, PrivateKey}; +use serde::Deserialize; + +pub mod function_calls; +pub mod proxy_calls; +pub mod report; + +#[derive(Debug, Deserialize)] +struct ArbOtherFields { + #[serde(rename = "gasUsedForL1")] + gas_used_for_l1: U128, + #[allow(dead_code)] + #[serde(rename = "l1BlockNumber")] + l1_block_number: String, +} + +/// Cache options for the contract. +/// `Bid(0)` will likely cache the contract on the nitro test node. +pub enum CacheOpt { + None, + Bid(u32), +} + +type ArbTxReceipt = + WithOtherFields>>; + +async fn deploy( + account: &Account, + contract_name: &str, + args: Option, + cache_opt: CacheOpt, +) -> eyre::Result
{ + let manifest_dir = + std::env::current_dir().context("should get current dir from env")?; + + let wasm_path = manifest_dir + .join("target") + .join("wasm32-unknown-unknown") + .join("release") + .join(format!("{}_example.wasm", contract_name.replace('-', "_"))); + let sol_path = args.as_ref().map(|_| { + manifest_dir + .join("examples") + .join(contract_name) + .join("src") + .join("constructor.sol") + }); + + let pk = account.pk(); + let config = Deploy { + generate_config: Generate { + wasm: wasm_path.clone(), + sol: sol_path, + args, + legacy: false, + }, + auth: PrivateKey { + private_key_path: None, + private_key: Some(pk), + keystore_path: None, + keystore_password_path: None, + }, + endpoint: env("RPC_URL")?, + deploy_only: false, + quiet: true, + }; + + let address = koba::deploy(&config) + .await + .expect("should deploy contract") + .address()?; + + if let CacheOpt::Bid(bid) = cache_opt { + cache_contract(account, address, bid)?; + } + + Ok(address) +} + +/// Try to cache a contract on the stylus network. +/// Already cached contracts won't be cached, and this function will not return +/// an error. +/// Output will be forwarded to the child process. +fn cache_contract( + account: &Account, + contract_addr: Address, + bid: u32, +) -> eyre::Result<()> { + // We don't need a status code. + // Since it is not zero when the contract is already cached. + let _ = Command::new("cargo") + .args(["stylus", "cache", "bid"]) + .args(["-e", &env("RPC_URL")?]) + .args(["--private-key", &format!("0x{}", account.pk())]) + .arg(contract_addr.to_string()) + .arg(bid.to_string()) + .status() + .context("failed to execute `cargo stylus cache bid` command")?; + Ok(()) +} + +/// Load the `name` environment variable. +fn env(name: &str) -> eyre::Result { + std::env::var(name).wrap_err(format!("failed to load {name}")) +} diff --git a/target_chains/ethereum/sdk/stylus/benches/src/main.rs b/target_chains/ethereum/sdk/stylus/benches/src/main.rs new file mode 100644 index 0000000000..868c6af12a --- /dev/null +++ b/target_chains/ethereum/sdk/stylus/benches/src/main.rs @@ -0,0 +1,18 @@ +use benches::{function_calls, proxy_calls, report::BenchmarkReport}; +use futures::FutureExt; + +#[tokio::main] +async fn main() -> eyre::Result<()> { + let report = futures::future::try_join_all([ + function_calls::bench().boxed(), + proxy_calls::bench().boxed(), + ]) + .await? + .into_iter() + .fold(BenchmarkReport::default(), BenchmarkReport::merge_with); + + println!(); + println!("{report}"); + + Ok(()) +} diff --git a/target_chains/ethereum/sdk/stylus/benches/src/proxy_calls.rs b/target_chains/ethereum/sdk/stylus/benches/src/proxy_calls.rs new file mode 100644 index 0000000000..c45e88e784 --- /dev/null +++ b/target_chains/ethereum/sdk/stylus/benches/src/proxy_calls.rs @@ -0,0 +1,103 @@ +use std::str::FromStr; + +use alloy::{ + network::{AnyNetwork, EthereumWallet}, + primitives::{uint, Address, FixedBytes as TypeFixedBytes}, + providers::ProviderBuilder, + sol, + sol_types::{SolCall, SolConstructor}, +}; +use e2e::{env, receipt, Account}; +use pyth_stylus::pyth::mock::create_price_feed_update_data_list; + +use crate::{ + report::{ContractReport, FunctionReport}, + CacheOpt, +}; + +sol!( + #[sol(rpc)] + contract ProxyCall{ + function getPriceUnsafe(bytes32 id) external returns (uint8[] price); + function getEmaPriceUnsafe(bytes32 id) external returns (uint8[] price); + function getPriceNoOlderThan(bytes32 id, uint age) external returns (uint8[] price); + function getEmaPriceNoOlderThan(bytes32 id, uint age) external returns (uint8[] price); + function getUpdateFee(bytes[] calldata updateData) external returns (uint256 fee); + function getValidTimePeriod() external returns (uint256 period); + function updatePriceFeeds(bytes[] calldata updateData) external payable; + function updatePriceFeedsIfNecessary(bytes[] calldata updateData, bytes32[] calldata priceIds, uint64[] calldata publishTimes) external payable; + } +); + +sol!("../examples/proxy-calls/src/constructor.sol"); + +pub async fn bench() -> eyre::Result { + let reports = run_with(CacheOpt::None).await?; + let report = reports + .into_iter() + .try_fold(ContractReport::new("ProxyCalls"), ContractReport::add)?; + + let cached_reports = run_with(CacheOpt::Bid(0)).await?; + let report = cached_reports + .into_iter() + .try_fold(report, ContractReport::add_cached)?; + + Ok(report) +} + +pub async fn run_with( + cache_opt: CacheOpt, +) -> eyre::Result> { + let alice = Account::new().await?; + let alice_wallet = ProviderBuilder::new() + .network::() + .with_recommended_fillers() + .wallet(EthereumWallet::from(alice.signer.clone())) + .on_http(alice.url().parse()?); + + let contract_addr = deploy(&alice, cache_opt).await?; + + let contract = ProxyCall::new(contract_addr, &alice_wallet); + let id = keccak_const::Keccak256::new().update(b"ETH").finalize().to_vec(); + let id = TypeFixedBytes::<32>::from_slice(&id); + let time_frame = uint!(10000_U256); + let age = uint!(10000_U256); + + let (data, _ids) = create_price_feed_update_data_list(); + + let _ = receipt!(contract.getPriceUnsafe(id))?; + let _ = receipt!(contract.getEmaPriceUnsafe(id))?; + let _ = receipt!(contract.getPriceNoOlderThan(id, age))?; + let _ = receipt!(contract.getEmaPriceNoOlderThan(id, age))?; + let _ = receipt!(contract.getValidTimePeriod())?; + let _ = receipt!(contract.getUpdateFee(data.clone()))?; + let _ = receipt!(contract.updatePriceFeeds(data.clone()))?; + + // IMPORTANT: Order matters! + use ProxyCall::*; + #[rustfmt::skip] + let receipts = vec![ + (getPriceUnsafeCall::SIGNATURE, receipt!(contract.getPriceUnsafe(id))?), + (getEmaPriceUnsafeCall::SIGNATURE, receipt!(contract.getEmaPriceUnsafe(id))?), + (getPriceNoOlderThanCall::SIGNATURE, receipt!(contract.getPriceNoOlderThan(id, time_frame))?), + (getEmaPriceNoOlderThanCall::SIGNATURE, receipt!(contract.getEmaPriceNoOlderThan(id, time_frame))?), + (getValidTimePeriodCall::SIGNATURE, receipt!(contract.getValidTimePeriod())?), + (getUpdateFeeCall::SIGNATURE, receipt!(contract.getUpdateFee(data.clone()))?), + ]; + + receipts + .into_iter() + .map(FunctionReport::new) + .collect::>>() +} + +async fn deploy( + account: &Account, + cache_opt: CacheOpt, +) -> eyre::Result
{ + let pyth_addr = env("MOCK_PYTH_ADDRESS")?; + let address = Address::from_str(&pyth_addr)?; + let args = ProxyCallsExample::constructorCall { _pythAddress: address }; + let args = alloy::hex::encode(args.abi_encode()); + crate::deploy(account, "proxy-calls", Some(args), cache_opt).await +} diff --git a/target_chains/ethereum/sdk/stylus/benches/src/report.rs b/target_chains/ethereum/sdk/stylus/benches/src/report.rs new file mode 100644 index 0000000000..49b5fe70f9 --- /dev/null +++ b/target_chains/ethereum/sdk/stylus/benches/src/report.rs @@ -0,0 +1,157 @@ +use std::{collections::HashMap, fmt::Display}; + +use crate::{ArbOtherFields, ArbTxReceipt}; + +const SEPARATOR: &str = "::"; + +#[derive(Debug)] +pub struct FunctionReport { + sig: String, + gas: u128, +} + +impl FunctionReport { + pub(crate) fn new(receipt: (&str, ArbTxReceipt)) -> eyre::Result { + Ok(FunctionReport { + sig: receipt.0.to_owned(), + gas: get_l2_gas_used(&receipt.1)?, + }) + } +} + +#[derive(Debug)] +pub struct ContractReport { + contract: String, + functions: Vec, + functions_cached: Vec, +} + +impl ContractReport { + pub fn new(contract: &str) -> Self { + ContractReport { + contract: contract.to_owned(), + functions: vec![], + functions_cached: vec![], + } + } + + pub fn add(mut self, fn_report: FunctionReport) -> eyre::Result { + self.functions.push(fn_report); + Ok(self) + } + + pub fn add_cached( + mut self, + fn_report: FunctionReport, + ) -> eyre::Result { + self.functions_cached.push(fn_report); + Ok(self) + } + + fn signature_max_len(&self) -> usize { + let prefix_len = self.contract.len() + SEPARATOR.len(); + self.functions + .iter() + .map(|FunctionReport { sig: name, .. }| prefix_len + name.len()) + .max() + .unwrap_or_default() + } + + fn gas_max_len(&self) -> usize { + self.functions + .iter() + .map(|FunctionReport { gas, .. }| gas.to_string().len()) + .max() + .unwrap_or_default() + } + + fn gas_cached_max_len(&self) -> usize { + self.functions_cached + .iter() + .map(|FunctionReport { gas, .. }| gas.to_string().len()) + .max() + .unwrap_or_default() + } +} + +#[derive(Debug, Default)] +pub struct BenchmarkReport(Vec); + +impl BenchmarkReport { + pub fn merge_with(mut self, report: ContractReport) -> Self { + self.0.push(report); + self + } + + pub fn column_width( + &self, + column_value: impl FnMut(&ContractReport) -> usize, + header: &str, + ) -> usize { + self.0 + .iter() + .map(column_value) + .chain(std::iter::once(header.len())) + .max() + .unwrap_or_default() + } +} + +impl Display for BenchmarkReport { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + const HEADER_SIG: &str = "Contract::function"; + const HEADER_GAS_CACHED: &str = "Cached"; + const HEADER_GAS: &str = "Not Cached"; + + // Calculating the width of table columns. + let width1 = + self.column_width(ContractReport::signature_max_len, HEADER_SIG); + let width2 = self.column_width( + ContractReport::gas_cached_max_len, + HEADER_GAS_CACHED, + ); + let width3 = self.column_width(ContractReport::gas_max_len, HEADER_GAS); + + // Print headers for the table columns. + writeln!( + f, + "| {HEADER_SIG:width2$} | {HEADER_GAS:>width3$} |" + )?; + writeln!( + f, + "| {:->width1$} | {:->width2$} | {:->width3$} |", + "", "", "" + )?; + + // Merging a non-cached gas report with a cached one. + for report in &self.0 { + let prefix = format!("{}{SEPARATOR}", report.contract); + let gas: HashMap<_, _> = report + .functions + .iter() + .map(|func| (&*func.sig, func.gas)) + .collect(); + + for report_cached in &report.functions_cached { + let sig = &*report_cached.sig; + let gas_cached = &report_cached.gas; + let gas = gas[sig]; + + let full_sig = format!("{prefix}{sig}"); + writeln!( + f, + "| {full_sig:width2$} | {gas:>width3$} |" + )?; + } + } + + Ok(()) + } +} + +fn get_l2_gas_used(receipt: &ArbTxReceipt) -> eyre::Result { + let l2_gas = receipt.gas_used; + let arb_fields: ArbOtherFields = receipt.other.deserialize_as()?; + let l1_gas = arb_fields.gas_used_for_l1.to::(); + Ok(l2_gas - l1_gas) +} diff --git a/target_chains/ethereum/sdk/stylus/contracts/Cargo.toml b/target_chains/ethereum/sdk/stylus/contracts/Cargo.toml new file mode 100644 index 0000000000..1183eb7cf7 --- /dev/null +++ b/target_chains/ethereum/sdk/stylus/contracts/Cargo.toml @@ -0,0 +1,35 @@ +[package] +name = "pyth-stylus" +authors.workspace = true +license.workspace = true +repository.workspace = true +version.workspace = true +edition.workspace = true + +[dependencies] +alloy-primitives.workspace = true +alloy-sol-types.workspace = true +alloy-sol-macro.workspace = true +alloy-sol-macro-expander.workspace = true +alloy-sol-macro-input.workspace = true +stylus-sdk.workspace = true +mini-alloc.workspace = true +keccak-const.workspace = true + +[dev-dependencies] +motsu.workspace = true +alloy-primitives = { workspace = true, features = ["arbitrary"] } + +[features] +# Enables using the standard library. This is not included in the default +# features, because this crate is meant to be used in a `no_std` environment. +# Currently, the std feature is only used for testing purposes. +std = [] + +[lib] +crate-type = ["lib", "cdylib"] + +[lints] +workspace = true + + diff --git a/target_chains/ethereum/sdk/stylus/contracts/src/lib.rs b/target_chains/ethereum/sdk/stylus/contracts/src/lib.rs new file mode 100644 index 0000000000..e9ba86fa6d --- /dev/null +++ b/target_chains/ethereum/sdk/stylus/contracts/src/lib.rs @@ -0,0 +1,23 @@ +#![allow(missing_docs)] +#![allow(clippy::pub_underscore_fields, clippy::module_name_repetitions)] +#![cfg_attr(not(feature = "std"), no_std, no_main)] +#![deny(rustdoc::broken_intra_doc_links)] + +extern crate alloc; + +#[global_allocator] +static ALLOC: mini_alloc::MiniAlloc = mini_alloc::MiniAlloc::INIT; + +/// Utility functions for interacting with the Pyth oracle. +/// This module contains functions for interacting with the Pyth oracle. +pub mod utils; + +/// Pyth contract for interacting with the Pyth oracle. +/// This module contains the types and functions for interacting with the Pyth oracle. +pub mod pyth; + +#[cfg(target_arch = "wasm32")] +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + loop {} +} diff --git a/target_chains/ethereum/sdk/stylus/contracts/src/pyth/errors.rs b/target_chains/ethereum/sdk/stylus/contracts/src/pyth/errors.rs new file mode 100644 index 0000000000..c5dca30128 --- /dev/null +++ b/target_chains/ethereum/sdk/stylus/contracts/src/pyth/errors.rs @@ -0,0 +1,120 @@ +use alloy_sol_types::sol; +use stylus_sdk::{call::MethodError, prelude::*}; + +sol! { + // Function arguments are invalid (e.g., the arguments lengths mismatch) + // Signature: 0xa9cb9e0d + #[derive(Debug)] + #[allow(missing_docs)] + error InvalidArgument(); + + // Update data is coming from an invalid data source. + // Signature: 0xe60dce71 + #[derive(Debug)] + #[allow(missing_docs)] + error InvalidUpdateDataSource(); + + // Update data is invalid (e.g., deserialization error) + // Signature: 0xe69ffece + #[derive(Debug)] + #[allow(missing_docs)] + error InvalidUpdateData(); + + // Insufficient fee is paid to the method. + // Signature: 0x025dbdd4 + #[derive(Debug)] + #[allow(missing_docs)] + error InsufficientFee(); + + // There is no fresh update, whereas expected fresh updates. + // Signature: 0xde2c57fa + #[derive(Debug)] + #[allow(missing_docs)] + error NoFreshUpdate(); + + // There is no price feed found within the given range or it does not exists. + // Signature: 0x45805f5d + #[derive(Debug)] + #[allow(missing_docs)] + error PriceFeedNotFoundWithinRange(); + + // Price feed not found or it is not pushed on-chain yet. + // Signature: 0x14aebe68 + #[derive(Debug)] + #[allow(missing_docs)] + error PriceFeedNotFound(); + + // Requested price is stale. + // Signature: 0x19abf40e + #[derive(Debug)] + #[allow(missing_docs)] + error StalePrice(); + + // Given message is not a valid Wormhole VAA. + // Signature: 0x2acbe915 + #[derive(Debug)] + #[allow(missing_docs)] + error InvalidWormholeVaa(); + + // Governance message is invalid (e.g., deserialization error). + // Signature: 0x97363b35 + #[derive(Debug)] + #[allow(missing_docs)] + error InvalidGovernanceMessage(); + + // Governance message is not for this contract. + // Signature: 0x63daeb77 + #[derive(Debug)] + #[allow(missing_docs)] + error InvalidGovernanceTarget(); + + // Governance message is coming from an invalid data source. + // Signature: 0x360f2d87 + #[derive(Debug)] + #[allow(missing_docs)] + error InvalidGovernanceDataSource(); + + // Governance message is old. + // Signature: 0x88d1b847 + #[derive(Debug)] + #[allow(missing_docs)] + error OldGovernanceMessage(); + + // The wormhole address to set in SetWormholeAddress governance is invalid. + // Signature: 0x13d3ed82 + #[derive(Debug)] + #[allow(missing_docs)] + error InvalidWormholeAddressToSet(); + + #[derive(Debug)] + #[allow(missing_docs)] + error FalledDecodeData(); + + +} + +/// A Pausable error. +#[derive(SolidityError, Debug)] +pub enum Error { + InvalidArgument(InvalidArgument), + InvalidUpdateDataSource(InvalidUpdateDataSource), + InvalidUpdateData(InvalidUpdateData), + InsufficientFee(InsufficientFee), + NoFreshUpdate(NoFreshUpdate), + PriceFeedNotFoundWithinRange(PriceFeedNotFoundWithinRange), + PriceFeedNotFound(PriceFeedNotFound), + StalePrice(StalePrice), + InvalidWormholeVaa(InvalidWormholeVaa), + InvalidGovernanceMessage(InvalidGovernanceMessage), + InvalidGovernanceTarget(InvalidGovernanceTarget), + InvalidGovernanceDataSource(InvalidGovernanceDataSource), + OldGovernanceMessage(OldGovernanceMessage), + InvalidWormholeAddressToSet(InvalidWormholeAddressToSet), + FalledDecodeData(FalledDecodeData), +} + +impl MethodError for Error { + fn encode(self) -> alloc::vec::Vec { + self.into() + } +} diff --git a/target_chains/ethereum/sdk/stylus/contracts/src/pyth/events.rs b/target_chains/ethereum/sdk/stylus/contracts/src/pyth/events.rs new file mode 100644 index 0000000000..fe2248df08 --- /dev/null +++ b/target_chains/ethereum/sdk/stylus/contracts/src/pyth/events.rs @@ -0,0 +1,10 @@ +use alloy_sol_types::sol; + +sol! { + event PriceFeedUpdate( + bytes32 indexed id, + uint64 publishTime, + int64 price, + uint64 conf + ); +} diff --git a/target_chains/ethereum/sdk/stylus/contracts/src/pyth/functions.rs b/target_chains/ethereum/sdk/stylus/contracts/src/pyth/functions.rs new file mode 100644 index 0000000000..771f6e48b4 --- /dev/null +++ b/target_chains/ethereum/sdk/stylus/contracts/src/pyth/functions.rs @@ -0,0 +1,281 @@ +use crate::pyth::mock::DecodeDataType; +use crate::pyth::types::{ + getEmaPriceNoOlderThanCall, getEmaPriceUnsafeCall, getPriceNoOlderThanCall, + getPriceUnsafeCall, getUpdateFeeCall, getValidTimePeriodCall, + parsePriceFeedUpdatesCall, parsePriceFeedUpdatesUniqueCall, + updatePriceFeedsCall, updatePriceFeedsIfNecessaryCall, Price, PriceFeed, +}; +use crate::utils::{call_helper, delegate_call_helper}; +use alloc::vec::Vec; +use alloy_primitives::{Address, Bytes, B256, U256}; +use alloy_sol_types::SolType; +use stylus_sdk::storage::TopLevelStorage; + +/// Retrieves the price for a given asset ID from the Pyth price feed, ensuring the price is not older than a specified age. +/// +/// # Parameters +/// - `storage`: A mutable reference to an implementation of `TopLevelStorage`. +/// - `pyth_address`: The address of the Pyth price feed contract. +/// - `id`: The fixed byte identifier for the asset whose price is being retrieved. +/// - `age`: The maximum allowed age of the price. +/// +/// # Returns +/// - `Result>`: A `Result` that contains the `Price` struct if successful, or an error message as a byte vector. +pub fn get_price_no_older_than( + storage: &mut impl TopLevelStorage, + pyth_address: Address, + id: B256, + age: U256, +) -> Result> { + let price_call = call_helper::( + storage, + pyth_address, + (id, age), + )?; + Ok(price_call.price) +} + +/// Queries the contract for the fee required to update price data, given the update data as input. +/// +/// # Parameters +/// - `storage`: A mutable reference to an implementation of `TopLevelStorage`. +/// - `pyth_address`: The address of the Pyth price feed contract. +/// - `update_data`: A vector of bytes containing the data required for the update. +/// +/// # Returns +/// - `Result>`: A `Result` containing the update fee as a `U256` if successful, or an error message as a byte vector. +pub fn get_update_fee( + storage: &mut impl TopLevelStorage, + pyth_address: Address, + update_data: Vec, +) -> Result> { + let update_fee_call = + call_helper::(storage, pyth_address, (update_data,))?; + Ok(update_fee_call.feeAmount) +} + +/// Retrieves the Exponential Moving Average (EMA) price for a specific asset ID without safety checks. +/// +/// # Parameters +/// - `storage`: A mutable reference to an implementation of `TopLevelStorage`. +/// - `pyth_address`: The address of the Pyth price feed contract. +/// - `id`: The fixed byte identifier for the asset whose EMA price is being retrieved. +/// +/// # Returns +/// - `Result>`: A `Result` containing the `Price` struct if successful, or an error message as a byte vector. +pub fn get_ema_price_unsafe( + storage: &mut impl TopLevelStorage, + pyth_address: Address, + id: B256, +) -> Result> { + let ema_price = + call_helper::(storage, pyth_address, (id,))?; + Ok(ema_price.price) +} + +/// Similar to `get_ema_price_unsafe`, but ensures the EMA price is not older than a specified age. +/// +/// # Parameters +/// - `storage`: A mutable reference to an implementation of `TopLevelStorage`. +/// - `pyth_address`: The address of the Pyth price feed contract. +/// - `id`: The fixed byte identifier for the asset whose EMA price is being retrieved. +/// - `age`: The maximum allowed age of the EMA price. +/// +/// # Returns +/// - `Result>`: A `Result` containing the `Price` struct if successful, or an error message as a byte vector. +pub fn get_ema_price_no_older_than( + storage: &mut impl TopLevelStorage, + pyth_address: Address, + id: B256, + age: U256, +) -> Result> { + let ema_price = call_helper::( + storage, + pyth_address, + (id, age), + )?; + Ok(ema_price.price) +} + +/// Retrieves the current price for a given asset ID without safety checks, constructing a `Price` struct from raw values. +/// +/// # Parameters +/// - `storage`: A mutable reference to an implementation of `TopLevelStorage`. +/// - `pyth_address`: The address of the Pyth price feed contract. +/// - `id`: The fixed byte identifier for the asset whose price is being retrieved. +/// +/// # Returns +/// - `Result>`: A `Result` containing the constructed `Price` struct if successful, or an error message as a byte vector. +pub fn get_price_unsafe( + storage: &mut impl TopLevelStorage, + pyth_address: Address, + id: B256, +) -> Result> { + let price = + call_helper::(storage, pyth_address, (id,))?; + let price = Price { + price: price._0, + conf: price._1, + expo: price._2, + publish_time: price._3, + }; + Ok(price) +} + +/// Queries the Pyth contract to get the valid time period for price feeds. +/// +/// # Parameters +/// - `storage`: A mutable reference to an implementation of `TopLevelStorage`. +/// - `pyth_address`: The address of the Pyth price feed contract. +/// +/// # Returns +/// - `Result>`: A `Result` containing the valid time period as a `U256` if successful, or an error message as a byte vector. +pub fn get_valid_time_period( + storage: &mut impl TopLevelStorage, + pyth_address: Address, +) -> Result> { + let valid_time_period = + call_helper::(storage, pyth_address, ())?; + Ok(valid_time_period.validTimePeriod) +} + +/// Updates the price feeds in the Pyth contract using the provided update data. +/// +/// # Parameters +/// - `storage`: A mutable reference to an implementation of `TopLevelStorage`. +/// - `pyth_address`: The address of the Pyth price feed contract. +/// - `update_data`: A vector of bytes containing the data required for the update. +/// +/// # Returns +/// - `Result<(), Vec>`: A `Result` that indicates success or failure, returning an error message as a byte vector if unsuccessful. +pub fn update_price_feeds( + storage: &mut impl TopLevelStorage, + pyth_address: Address, + update_data: Vec, +) -> Result<(), Vec> { + delegate_call_helper::( + storage, + pyth_address, + (update_data,), + )?; + Ok(()) +} + +/// Updates price feeds only if necessary, based on provided price IDs and publish times. +/// +/// # Parameters +/// - `storage`: A mutable reference to an implementation of `TopLevelStorage`. +/// - `pyth_address`: The address of the Pyth price feed contract. +/// - `update_data`: A vector of bytes containing the data required for the update. +/// - `price_ids`: A vector of fixed byte identifiers for the assets to update. +/// - `publish_times`: A vector of timestamps indicating when the prices were published. +/// +/// # Returns +/// - `Result<(), Vec>`: A `Result` that indicates success or failure, returning an error message as a byte vector if unsuccessful. +pub fn update_price_feeds_if_necessary( + storage: &mut impl TopLevelStorage, + pyth_address: Address, + update_data: Vec, + price_ids: Vec, + publish_times: Vec, +) -> Result<(), Vec> { + delegate_call_helper::( + storage, + pyth_address, + (update_data, price_ids, publish_times), + )?; + Ok(()) +} + +/// Parses the updates to price feeds, returning a vector of `PriceFeed` structs based on the provided time range. +/// +/// # Parameters +/// - `storage`: A mutable reference to an implementation of `TopLevelStorage`. +/// - `pyth_address`: The address of the Pyth price feed contract. +/// - `update_data`: A vector of bytes containing the data required for the updates. +/// - `price_ids`: A vector of fixed byte identifiers for the assets being updated. +/// - `min_publish_time`: The minimum publish time to consider for the updates. +/// - `max_publish_time`: The maximum publish time to consider for the updates. +/// +/// # Returns +/// - `Result, Vec>`: A `Result` containing a vector of `PriceFeed` structs if successful, or an error message as a byte vector. +pub fn parse_price_feed_updates( + storage: &mut impl TopLevelStorage, + pyth_address: Address, + update_data: Vec, + price_ids: Vec, + min_publish_time: u64, + max_publish_time: u64, +) -> Result, Vec> { + let parse_price_feed_updates_call = + delegate_call_helper::( + storage, + pyth_address, + (update_data, price_ids, min_publish_time, max_publish_time), + )?; + Ok(parse_price_feed_updates_call.priceFeeds) +} + +/// Similar to `parse_price_feed_updates`, but only returns the latest price feed for each asset if multiple updates are available. +/// +/// # Parameters +/// - `storage`: A mutable reference to an implementation of `TopLevelStorage`. +/// - `pyth_address`: The address of the Pyth price feed contract. +/// - `update_data`: A vector of bytes containing the data required for the updates. +/// - `price_ids`: A vector of fixed byte identifiers for the assets being updated. +/// - `min_publish_time`: The minimum publish time to consider for the updates. +/// - `max_publish_time`: The maximum publish time to consider for the updates. +/// +/// # Returns +/// - `Result, Vec>`: A `Result` containing a vector of `PriceFeed` structs if successful, or an error message as a byte vector. +pub fn parse_price_feed_updates_unique( + storage: &mut impl TopLevelStorage, + pyth_address: Address, + update_data: Vec, + price_ids: Vec, + min_publish_time: u64, + max_publish_time: u64, +) -> Result, Vec> { + let parse_price_feed_updates_call = + delegate_call_helper::( + storage, + pyth_address, + (update_data, price_ids, min_publish_time, max_publish_time), + )?; + Ok(parse_price_feed_updates_call.priceFeeds) +} + +/// Creates the update data required for a price feed, encapsulating the current price, confidence interval, +/// exponential moving average (EMA) price, and other relevant details. +/// +/// # Parameters +/// - `id`: The fixed byte identifier for the asset being updated. +/// - `price`: The current price of the asset as a 64-bit signed integer. +/// - `conf`: The confidence level of the current price as a 64-bit unsigned integer. +/// - `expo`: The exponent for the price, indicating its precision. +/// - `ema_price`: The Exponential Moving Average price of the asset as a 64-bit signed integer. +/// - `ema_conf`: The confidence level of the EMA price as a 64-bit unsigned integer. +/// - `publish_time`: The time the price was published, represented as a `U256`. +/// - `prev_publish_time`: The previous publish time of the price, represented as a 64-bit unsigned integer. +/// +/// # Returns +/// - `Vec`: A byte vector containing the encoded update data for the price feed. +pub fn create_price_feed_update_data( + id: B256, + price: i64, + conf: u64, + expo: i32, + ema_price: i64, + ema_conf: u64, + publish_time: U256, + prev_publish_time: u64, +) -> Vec { + let price = Price { price, conf, expo, publish_time }; + let ema_price = + Price { price: ema_price, conf: ema_conf, expo, publish_time }; + + let price_feed_data = PriceFeed { id, price, ema_price }; + + let price_feed_data_encoding = (price_feed_data, prev_publish_time); + return DecodeDataType::abi_encode(&price_feed_data_encoding); +} diff --git a/target_chains/ethereum/sdk/stylus/contracts/src/pyth/mock.rs b/target_chains/ethereum/sdk/stylus/contracts/src/pyth/mock.rs new file mode 100644 index 0000000000..ce9b575238 --- /dev/null +++ b/target_chains/ethereum/sdk/stylus/contracts/src/pyth/mock.rs @@ -0,0 +1,365 @@ +use crate::pyth::errors::{Error, PriceFeedNotFound}; +use crate::pyth::events::PriceFeedUpdate; +use crate::pyth::functions::create_price_feed_update_data; +use crate::pyth::types::{Price, PriceFeed, StoragePriceFeed}; +use crate::{ + pyth::errors::{FalledDecodeData, InsufficientFee, InvalidArgument}, + utils::CALL_RETDATA_DECODING_ERROR_MESSAGE, +}; +use alloc::vec::Vec; +use alloy_primitives::{Bytes, B256, U256}; +use alloy_sol_types::{sol_data::Uint as SolUInt, SolType, SolValue}; +use stylus_sdk::{abi::Bytes as AbiBytes, evm, msg, prelude::*}; + +////Decode data type PriceFeed and uint64 +pub type DecodeDataType = (PriceFeed, SolUInt<64>); + +sol_storage! { + struct MockPythContract { + uint single_update_fee_in_wei; + uint valid_time_period; + mapping(bytes32 => StoragePriceFeed) price_feeds; + } +} + +#[public] +impl MockPythContract { + fn initialize( + &mut self, + single_update_fee_in_wei: U256, + valid_time_period: U256, + ) -> Result<(), Vec> { + if single_update_fee_in_wei <= U256::ZERO + || valid_time_period <= U256::ZERO + { + return Err(Error::InvalidArgument(InvalidArgument {}).into()); + } + self.single_update_fee_in_wei.set(single_update_fee_in_wei); + self.valid_time_period.set(valid_time_period); + Ok(()) + } + + fn query_price_feed(&self, id: B256) -> Result, Vec> { + let price_feed = self.price_feeds.get(id).to_price_feed(); + if price_feed.id.is_zero() { + return Err(Error::PriceFeedNotFound(PriceFeedNotFound {}).into()); + } + Ok(price_feed.abi_encode()) + } + + fn price_feed_exists(&self, id: B256) -> bool { + self.price_feeds.getter(id).id.is_empty() + } + + fn get_valid_time_period(&self) -> U256 { + self.valid_time_period.get() + } + + /// Takes an array of encoded price feeds and stores them. + /// You can create this data either by calling createPriceFeedUpdateData or + /// by using web3.js or ethers abi utilities. + /// @note: The updateData expected here is different from the one used in the main contract. + /// In particular, the expected format is: + /// [ + /// abi.encode( + /// PythStructs.PriceFeed( + /// bytes32 id, + /// PythStructs.Price price, + /// PythStructs.Price emaPrice + /// ), + /// uint64 prevPublishTime + /// ) + /// ] + + #[payable] + fn update_price_feeds( + &mut self, + update_data: Vec, + ) -> Result<(), Vec> { + let required_fee = self.get_update_fee(update_data.clone()); + if required_fee < msg::value() { + return Err(Error::InsufficientFee(InsufficientFee {}).into()); + } + + for i in 0..update_data.len() { + let price_feed_data = + ::abi_decode(&update_data[i], false) + .map_err(|_| { + CALL_RETDATA_DECODING_ERROR_MESSAGE.to_vec() + })?; + let last_publish_time = + &self.price_feeds.get(price_feed_data.id).price.publish_time.get(); + if last_publish_time < &price_feed_data.price.publish_time { + self.price_feeds + .setter(price_feed_data.id) + .set(price_feed_data); + evm::log(PriceFeedUpdate { + id: price_feed_data.id, + publishTime: price_feed_data.price.publish_time.to(), + price: price_feed_data.price.price, + conf: price_feed_data.price.conf, + }); + } + } + Ok(()) + } + + fn get_update_fee(&self, update_data: Vec) -> U256 { + self.single_update_fee_in_wei.get() * U256::from(update_data.len()) + } + #[payable] + fn parse_price_feed_updates( + &mut self, + update_data: Vec, + price_ids: Vec, + min_publish_time: u64, + max_publish_time: u64, + ) -> Result, Vec> { + self.parse_price_feed_updates_internal( + update_data, + price_ids, + min_publish_time, + max_publish_time, + false, + ) + } + + #[payable] + fn parse_price_feed_updates_unique( + &mut self, + update_data: Vec, + price_ids: Vec, + min_publish_time: u64, + max_publish_time: u64, + ) -> Result, Vec> { + self.parse_price_feed_updates_internal( + update_data, + price_ids, + min_publish_time, + max_publish_time, + true, + ) + } + + fn create_price_feed_update_data( + &self, + id: B256, + price: i64, + conf: u64, + expo: i32, + ema_price: i64, + ema_conf: u64, + publish_time: U256, + prev_publish_time: u64, + ) -> Vec { + let price = Price { price, conf, expo, publish_time }; + let ema_price = + Price { price: ema_price, conf: ema_conf, expo, publish_time }; + + let price_feed_data = PriceFeed { id, price, ema_price }; + + let price_feed_data_encoding = (price_feed_data, prev_publish_time); + return DecodeDataType::abi_encode(&price_feed_data_encoding); + } +} + +impl MockPythContract { + fn parse_price_feed_updates_internal( + &mut self, + update_data: Vec, + price_ids: Vec, + min_publish_time: u64, + max_publish_time: u64, + unique: bool, + ) -> Result, Vec> { + let required_fee = self.get_update_fee(update_data.clone()); + if required_fee < msg::value() { + return Err(Error::InsufficientFee(InsufficientFee {}).into()); + } + + let mut feeds = Vec::::with_capacity(price_ids.len()); + + for i in 0..price_ids.len() { + for j in 0..update_data.len() { + let (price_feed, prev_publish_time) = + match DecodeDataType::abi_decode(&update_data[j], false) { + Ok(res) => res, + Err(_) => { + return Err(Error::FalledDecodeData( + FalledDecodeData {}, + ) + .into()) + } + }; + feeds[j] = price_feed.clone(); + + let publish_time = price_feed.price.publish_time; + if self + .price_feeds + .get(feeds[i].id) + .price + .publish_time.get() < publish_time + { + self.price_feeds.setter(feeds[i].id).set(feeds[i]); + evm::log(PriceFeedUpdate { + id: feeds[i].id, + publishTime: publish_time.to(), + price: feeds[i].price.price, + conf: feeds[i].price.conf, + }); + } + + if feeds[i].id == price_ids[i] { + if publish_time > U256::from(min_publish_time) + && publish_time <= U256::from(max_publish_time) + && (!unique || prev_publish_time < min_publish_time) + { + break; + } else { + feeds[i].id = B256::ZERO; + } + } + } + + if feeds[i].id != price_ids[i] { + return Err(Error::FalledDecodeData(FalledDecodeData {}).into()); + } + } + Ok(feeds.abi_encode()) + } +} + +pub fn create_price_feed_update_data_list() -> (Vec, Vec) { + let id = ["ETH", "SOL", "BTC"].map(|x| { + let x = keccak_const::Keccak256::new() + .update(x.as_bytes()) + .finalize() + .to_vec(); + return B256::from_slice(&x); + }); + let mut price_feed_data_list = Vec::new(); + for i in 0..3 { + let price_feed_data = create_price_feed_update_data( + id[i], + 100, + 100, + 100, + 100, + 100, + U256::from(U256::MAX - U256::from(10)), + 0, + ); + let price_feed_data = Bytes::from(AbiBytes::from(price_feed_data).0); + price_feed_data_list.push(price_feed_data); + } + return (price_feed_data_list, id.to_vec()); +} + +#[cfg(all(test, feature = "std"))] +mod tests { + use crate::pyth::mock::{DecodeDataType, MockPythContract}; + use alloc::vec; + use alloy_primitives::{B256, U256}; + use alloy_sol_types::SolType; + use stylus_sdk::abi::Bytes; + + /// Updated constants to use uppercase naming convention + const PRICE: i64 = 1000; + const CONF: u64 = 1000; + const EXPO: i32 = 1000; + const EMA_PRICE: i64 = 1000; + const EMA_CONF: u64 = 1000; + const PREV_PUBLISH_TIME: u64 = 1000; + + fn generate_bytes() -> B256 { + B256::repeat_byte(30) + } + + #[motsu::test] + fn can_initialize_mock_contract(contract: MockPythContract) { + let _ = contract.initialize(U256::from(1000), U256::from(1000)); + assert_eq!(contract.single_update_fee_in_wei.get(), U256::from(1000)); + assert_eq!(contract.valid_time_period.get(), U256::from(1000)); + } + + #[motsu::test] + fn error_initialize_mock_contract(contract: MockPythContract) { + let err = contract.initialize(U256::from(0), U256::from(0)); + assert!(err.is_err()) + } + + #[motsu::test] + fn created_price_feed_data(contract: MockPythContract) { + let _ = contract.initialize(U256::from(1000), U256::from(1000)); + let id = generate_bytes(); + let publish_time = U256::from(1000); + let price_feed_created = contract.create_price_feed_update_data( + id, + PRICE, + CONF, + EXPO, + EMA_PRICE, + EMA_CONF, + publish_time, + PREV_PUBLISH_TIME, + ); + let price_feed_decoded = + DecodeDataType::abi_decode(&price_feed_created, true).unwrap(); + assert_eq!(price_feed_decoded.0.id, id); + assert_eq!(price_feed_decoded.0.price.price, PRICE); + assert_eq!(price_feed_decoded.0.price.conf, CONF); + assert_eq!(price_feed_decoded.0.price.expo, EXPO); + assert_eq!(price_feed_decoded.0.ema_price.price, EMA_PRICE); + assert_eq!(price_feed_decoded.0.ema_price.conf, EMA_CONF); + assert_eq!(price_feed_decoded.1, PREV_PUBLISH_TIME); + } + + #[motsu::test] + fn can_get_update_fee(contract: MockPythContract) { + let _ = contract.initialize(U256::from(1000), U256::from(1000)); + let publish_time = U256::from(1000); + let mut update_data: Vec = vec![]; + let mut x = 0; + while x < 10 { + let id = generate_bytes(); + let price_feed_created = contract.create_price_feed_update_data( + id, + PRICE, + CONF, + EXPO, + EMA_PRICE, + EMA_CONF, + publish_time, + PREV_PUBLISH_TIME, + ); + update_data.push(Bytes::from(price_feed_created)); + x += 1; + } + let required_fee = contract.get_update_fee(update_data.clone()); + assert_eq!(required_fee, U256::from(1000 * x)); + } + + #[motsu::test] + fn price_feed_does_not_exist(contract: MockPythContract) { + let _ = contract.initialize(U256::from(1000), U256::from(1000)); + let id = generate_bytes(); + let price_feed_found = contract.price_feed_exists(id); + assert_eq!(price_feed_found, false); + } + + #[motsu::test] + fn query_price_feed_failed(contract: MockPythContract) { + let _ = contract.initialize(U256::from(1000), U256::from(1000)); + let id = generate_bytes(); + let _price_feed = contract + .query_price_feed(id) + .expect_err("should not query if price feed does not exist"); + } + + #[motsu::test] + fn can_get_valid_time_period(contract: MockPythContract) { + let _ = contract.initialize(U256::from(1000), U256::from(1000)); + let valid_time_period = contract.get_valid_time_period(); + assert_eq!(valid_time_period, U256::from(1000)); + } +} diff --git a/target_chains/ethereum/sdk/stylus/contracts/src/pyth/mod.rs b/target_chains/ethereum/sdk/stylus/contracts/src/pyth/mod.rs new file mode 100644 index 0000000000..2dc86c9887 --- /dev/null +++ b/target_chains/ethereum/sdk/stylus/contracts/src/pyth/mod.rs @@ -0,0 +1,13 @@ +mod errors; +mod events; +/// Types and functions for interacting with the Pyth oracle. +pub mod types; + +/// Mock module for testing +pub mod mock; + +/// Functions for interacting with the Pyth oracle. +pub mod functions; + +/// Contract for interacting with the Pyth oracle. +pub mod pyth_contract; diff --git a/target_chains/ethereum/sdk/stylus/contracts/src/pyth/pyth_contract.rs b/target_chains/ethereum/sdk/stylus/contracts/src/pyth/pyth_contract.rs new file mode 100644 index 0000000000..749ac8d74d --- /dev/null +++ b/target_chains/ethereum/sdk/stylus/contracts/src/pyth/pyth_contract.rs @@ -0,0 +1,288 @@ +use crate::pyth::functions::{ + get_ema_price_no_older_than, get_ema_price_unsafe, get_price_no_older_than, + get_price_unsafe, get_update_fee, get_valid_time_period, + parse_price_feed_updates, parse_price_feed_updates_unique, + update_price_feeds, update_price_feeds_if_necessary, +}; +use alloc::vec::Vec; +use alloy_primitives::{Bytes, B256, U256}; +use alloy_sol_types::SolValue; +use stylus_sdk::{ + abi::Bytes as AbiBytes, prelude::*, storage::TopLevelStorage, +}; +/// `IPyth` is a trait that defines methods for interacting with the Pyth contract. +pub trait IPyth { + /// The Error Type for the Pyth Contract. + /// - `Vec`: The error message in bytes. + type Error: Into>; + + /// Retrieves the latest price feed without any recency checks. + /// + /// # Parameters + /// - `id`: The unique identifier for the price feed. + /// + /// # Returns + /// - `Result, Self::Error>`: The price data in bytes, or an error. + fn get_price_unsafe(&mut self, id: B256) -> Result, Self::Error>; + + /// Retrieves a price that is no older than a specified `age`. + /// + /// # Parameters + /// - `id`: The unique identifier for the price feed. + /// - `age`: The maximum acceptable age of the price in seconds. + /// + /// # Returns + /// - `Result, Self::Error>`: The price data in bytes, or an error. + fn get_price_no_older_than( + &mut self, + id: B256, + age: U256, + ) -> Result, Self::Error>; + + /// Retrieves the exponentially-weighted moving average (EMA) price without recency checks. + /// + /// # Parameters + /// - `id`: The unique identifier for the price feed. + /// + /// # Returns + /// - `Result, Self::Error>`: The EMA price data in bytes, or an error. + fn get_ema_price_unsafe( + &mut self, + id: B256, + ) -> Result, Self::Error>; + + /// Retrieves an EMA price that is no older than the specified `age`. + /// + /// # Parameters + /// - `id`: The unique identifier for the price feed. + /// - `age`: The maximum acceptable age of the price in seconds. + /// + /// # Returns + /// - `Result, Self::Error>`: The EMA price data in bytes, or an error. + fn get_ema_price_no_older_than( + &mut self, + id: B256, + age: U256, + ) -> Result, Self::Error>; + + /// Updates price feeds with the given data. + /// + /// # Parameters + /// - `update_data`: Array of price update data. + /// + /// # Returns + /// - `Result<(), Self::Error>`: Success or error. + fn update_price_feeds( + &mut self, + update_data: Vec, + ) -> Result<(), Self::Error>; + + /// Updates price feeds if necessary, based on given publish times. + /// + /// # Parameters + /// - `update_data`: Array of price update data. + /// - `price_ids`: Array of price IDs. + /// - `publish_times`: Array of publish times for the corresponding price IDs. + /// + /// # Returns + /// - `Result<(), Self::Error>`: Success or error. + fn update_price_feeds_if_necessary( + &mut self, + update_data: Vec, + price_ids: Vec, + publish_times: Vec, + ) -> Result<(), Self::Error>; + + /// Returns the fee required to update the price feeds based on the provided data. + /// + /// # Parameters + /// - `update_data`: Array of price update data. + /// + /// # Returns + /// - `Result`: The required fee in Wei, or an error. + fn get_update_fee( + &mut self, + update_data: Vec, + ) -> Result; + + /// Returns the fee required to update the price feeds based on the provided data. + /// + /// # Parameters + /// - `update_data`: Array of price update data. + /// + /// # Returns + /// - `Result`: The required fee in Wei, or an error. + fn get_valid_time_period(&mut self) -> Result; + + /// Parses the price feed updates for specific price IDs within a given time range. + /// + /// # Parameters + /// - `update_data`: Array of price update data. + /// - `price_ids`: Array of price IDs to parse. + /// - `min_publish_time`: Minimum acceptable publish time for the price IDs. + /// - `max_publish_time`: Maximum acceptable publish time for the price IDs. + /// + /// # Returns + /// - `Result, Self::Error>`: Parsed price feed data in bytes, or an error. + fn parse_price_feed_updates( + &mut self, + update_data: Vec, + price_ids: Vec, + min_publish_time: u64, + max_publish_time: u64, + ) -> Result, Self::Error>; + + /// Parses price feed updates for specific price IDs, ensuring only the first updates within a time range are returned. + /// + /// # Parameters + /// - `update_data`: Array of price update data. + /// - `price_ids`: Array of price IDs to parse. + /// - `min_publish_time`: Minimum acceptable publish time for the price IDs. + /// - `max_publish_time`: Maximum acceptable publish time for the price IDs. + /// + /// # Returns + /// - `Result, Self::Error>`: Parsed price feed data in bytes, or an error. + fn parse_price_feed_updates_unique( + &mut self, + update_data: Vec, + price_ids: Vec, + min_publish_time: u64, + max_publish_time: u64, + ) -> Result, Self::Error>; +} + +sol_storage! { + /// `PythContract` represents the contract that interacts with the Pyth oracle. + /// This struct contains only the address of the Pyth contract. + pub struct PythContract { + /// `_ipyth` is the address of the deployed Pyth contract. + address _ipyth; + } +} + +unsafe impl TopLevelStorage for PythContract {} + +#[public] +impl IPyth for PythContract { + type Error = Vec; + + fn get_price_unsafe(&mut self, id: B256) -> Result, Self::Error> { + let price = get_price_unsafe(self, self._ipyth.get(), id)?; + let data = price.abi_encode(); + Ok(data) + } + + fn get_price_no_older_than( + &mut self, + id: B256, + age: U256, + ) -> Result, Self::Error> { + let price = get_price_no_older_than(self, self._ipyth.get(), id, age)?; + let data = price.abi_encode(); + Ok(data) + } + + fn get_ema_price_unsafe( + &mut self, + id: B256, + ) -> Result, Self::Error> { + let price = get_ema_price_unsafe(self, self._ipyth.get(), id)?; + let data = price.abi_encode(); + Ok(data) + } + + fn get_ema_price_no_older_than( + &mut self, + id: B256, + age: U256, + ) -> Result, Self::Error> { + let price = + get_ema_price_no_older_than(self, self._ipyth.get(), id, age)?; + let data = price.abi_encode(); + Ok(data) + } + + fn get_valid_time_period(&mut self) -> Result { + let time = get_valid_time_period(self, self._ipyth.get())?; + Ok(time) + } + + fn get_update_fee( + &mut self, + update_data: Vec, + ) -> Result { + let data = update_data.into_iter().map(|x| Bytes::from(x.0)).collect(); + let fee = get_update_fee(self, self._ipyth.get(), data)?; + Ok(fee) + } + + #[payable] + fn update_price_feeds( + &mut self, + update_data: Vec, + ) -> Result<(), Self::Error> { + let data = update_data.into_iter().map(|x| Bytes::from(x.0)).collect(); + update_price_feeds(self, self._ipyth.get(), data)?; + Ok(()) + } + + #[payable] + fn update_price_feeds_if_necessary( + &mut self, + update_data: Vec, + price_ids: Vec, + publish_times: Vec, + ) -> Result<(), Self::Error> { + let data = update_data.into_iter().map(|x| Bytes::from(x.0)).collect(); + update_price_feeds_if_necessary( + self, + self._ipyth.get(), + data, + price_ids, + publish_times, + )?; + Ok(()) + } + + #[payable] + fn parse_price_feed_updates( + &mut self, + update_data: Vec, + price_ids: Vec, + min_publish_time: u64, + max_publish_time: u64, + ) -> Result, Self::Error> { + let data = update_data.into_iter().map(|x| Bytes::from(x.0)).collect(); + let encode_data = parse_price_feed_updates( + self, + self._ipyth.get(), + data, + price_ids, + min_publish_time, + max_publish_time, + )? + .abi_encode(); + Ok(encode_data) + } + + #[payable] + fn parse_price_feed_updates_unique( + &mut self, + update_data: Vec, + price_ids: Vec, + min_publish_time: u64, + max_publish_time: u64, + ) -> Result, Self::Error> { + let data = update_data.into_iter().map(|x| Bytes::from(x.0)).collect(); + let encode_data = parse_price_feed_updates_unique( + self, + self._ipyth.get(), + data, + price_ids, + min_publish_time, + max_publish_time, + )? + .abi_encode(); + Ok(encode_data) + } +} diff --git a/target_chains/ethereum/sdk/stylus/contracts/src/pyth/types.rs b/target_chains/ethereum/sdk/stylus/contracts/src/pyth/types.rs new file mode 100644 index 0000000000..eb888f5484 --- /dev/null +++ b/target_chains/ethereum/sdk/stylus/contracts/src/pyth/types.rs @@ -0,0 +1,321 @@ +#![allow(missing_docs)] +//! Solidity type definitions used throughout the project +use alloy_primitives::{I32, I64, U256, U64}; +use stylus_sdk::{alloy_sol_types::sol, prelude::*}; + +sol_storage! { + /// Represents a storage-optimized price structure containing the current price data. + pub struct StoragePrice { + int64 price; + uint64 conf; + int32 expo; + uint publish_time; + } + + /// Represents a storage-optimized price feed structure containing an ID and associated price data. + pub struct StoragePriceFeed { + bytes32 id; + StoragePrice price; + StoragePrice ema_price; + } +} + +sol! { + /// Represents a price structure containing the current price data. + /// + /// # Fields + /// - `price`: The current price value as an `int64`. + /// - `conf`: The confidence level of the price as a `uint64`. + /// - `expo`: The exponent value indicating the scale of the price as an `int32`. + /// - `publish_time`: The timestamp of when the price was published as a `uint`. + #[derive(Debug, Copy)] + struct Price { + int64 price; + uint64 conf; + int32 expo; + uint publish_time; + } + + /// Represents a price feed structure containing an ID and associated price data. + /// + /// This struct is used solely as a return type for function selectors related + /// to price feeds in the SDK. + /// + /// # Fields + /// - `id`: The unique identifier for the price feed as a `bytes32`. + /// - `price`: The current price information as a `Price`. + /// - `ema_price`: The Exponential Moving Average (EMA) price information as a `Price`. + #[derive(Debug, Copy)] + struct PriceFeed { + bytes32 id; + Price price; + Price ema_price; + } + /// Function call selector: Fetches the price associated with the given ID without validation. + /// Returns the raw `Price` data for the specified `bytes32` ID, acting as a return call selector. + function getPriceUnsafe(bytes32 id) external view returns (int64,uint64,int32,uint); + + /// Function call selector: Retrieves the price associated with the given ID + /// ensuring that the price is not older than the specified age in seconds. + /// Returns the `Price` data for the specified `bytes32` ID. + function getPriceNoOlderThan( + bytes32 id, + uint age + ) external view returns (Price memory price); + + /// Function call selector: Fetches the Exponential Moving Average (EMA) price + /// associated with the given ID without validation. + /// Returns the raw `Price` data for the specified `bytes32` ID, acting as a return call selector. + function getEmaPriceUnsafe( + bytes32 id + ) external view returns (Price memory price); + + /// Function call selector: Retrieves the EMA price associated with the given ID + /// ensuring that the price is not older than the specified age in seconds. + /// Returns the `Price` data for the specified `bytes32` ID. + function getEmaPriceNoOlderThan( + bytes32 id, + uint age + ) external view returns (Price memory price); + + /// Function call selector: Updates multiple price feeds using the provided update data. + /// Accepts an array of `bytes` containing update data and processes the updates. + function updatePriceFeeds(bytes[] calldata updateData) external payable; + + /// Function call selector: Updates multiple price feeds only if necessary based on the provided conditions. + /// Accepts arrays of `bytes`, `bytes32`, and `uint64` to check against existing feeds + /// and processes the updates if conditions are met. + function updatePriceFeedsIfNecessary( + bytes[] calldata updateData, + bytes32[] calldata priceIds, + uint64[] calldata publishTimes + ) external payable; + + /// Function call selector: Calculates the fee amount required to update price feeds + /// based on the provided update data. + /// Returns the fee amount as a `uint`. + function getUpdateFee( + bytes[] calldata updateData + ) external view returns (uint feeAmount); + + /// Function call selector: Parses updates from the provided data for multiple price feeds. + /// Accepts arrays of `bytes` and `bytes32`, along with publish time constraints, + /// and returns an array of `PriceFeed` structs containing the parsed updates. + function parsePriceFeedUpdates( + bytes[] calldata updateData, + bytes32[] calldata priceIds, + uint64 minPublishTime, + uint64 maxPublishTime + ) external payable returns (PriceFeed[] memory priceFeeds); + + /// Function call selector: Parses updates from the provided data for unique price feeds. + /// Accepts arrays of `bytes` and `bytes32`, along with publish time constraints, + /// and returns an array of unique `PriceFeed` structs containing the parsed updates. + function parsePriceFeedUpdatesUnique( + bytes[] calldata updateData, + bytes32[] calldata priceIds, + uint64 minPublishTime, + uint64 maxPublishTime + ) external payable returns (PriceFeed[] memory priceFeeds); + + /// Function call selector: Queries the price feed for a given ID. + /// Returns an array of `PriceFeed` structs associated with the specified `bytes32` ID. + function queryPriceFeed( + bytes32 id + ) public view virtual returns (PriceFeed[] memory priceFeeds); + + /// Function call selector: Checks if a price feed exists for the given ID. + /// Returns an array of `PriceFeed` structs if it exists for the specified `bytes32` ID. + function priceFeedExists( + bytes32 id + ) public view virtual returns (PriceFeed[] memory priceFeeds); + + /// Function call selector: Retrieves the valid time period for price feeds. + /// Returns the valid time period as a `uint`. + function getValidTimePeriod() + public + view + virtual + returns (uint validTimePeriod); +} + +impl StoragePrice { + /// Converts the `StoragePrice` instance into a `Price` struct. + /// + /// This method retrieves the stored values from the `StoragePrice` + /// and creates a `Price` struct, making it suitable for external + /// use or return types in function calls. + pub fn to_price(&self) -> Price { + Price { + price: self.price.get().as_i64(), + conf: self.conf.get().to(), + expo: self.expo.get().as_i32(), + publish_time: self.publish_time.get(), + } + } + + /// Sets the values of the `StoragePrice` instance from a given `Price` struct. + /// This method updates the stored values in the `StoragePrice` with + /// the corresponding values from the provided `Price` struct, ensuring + /// that the internal state is accurately reflected. + pub fn set(&mut self, price: Price) { + self.price.set(I64::try_from(price.price).unwrap()); + self.conf.set(U64::try_from(price.conf).unwrap()); + self.expo.set(I32::try_from(price.expo).unwrap()); + self.publish_time.set(price.publish_time); + } + + /// This function is for just for testing + pub fn test_from_price(price: Price) -> Self { + let mut storage_price = + unsafe { StoragePrice::new(U256::from(100), 0) }; + storage_price.set(price); + storage_price + } +} + +impl StoragePriceFeed { + /// Converts the `StoragePriceFeed` instance into a `PriceFeed` struct. + /// + /// This method retrieves the stored price feed values and creates + /// a `PriceFeed` struct, which includes the unique identifier and + /// associated price data, making it suitable for external use or + /// return types in function calls. + pub fn to_price_feed(&self) -> PriceFeed { + PriceFeed { + id: self.id.get(), + price: self.price.to_price(), + ema_price: self.ema_price.to_price(), + } + } + + /// Sets the values of the `StoragePriceFeed` instance from a given `PriceFeed` struct. + /// + /// This method updates the stored values in the `StoragePriceFeed` + /// with the corresponding values from the provided `PriceFeed` struct, + /// ensuring that the internal state is accurately reflected. + pub fn set(&mut self, price_feed: PriceFeed) { + self.id.set(price_feed.id); + self.price.set(price_feed.price); + self.ema_price.set(price_feed.ema_price); + } + + /// This function is for just for testing + #[cfg(test)] + pub fn test_from_price_feed(price_feed: PriceFeed) -> Self { + let mut storage_price_feed = + unsafe { StoragePriceFeed::new(U256::from(100), 0) }; + storage_price_feed.set(price_feed); + storage_price_feed + } +} + +#[cfg(all(test, feature = "std"))] +mod tests { + use crate::pyth::types::{ + Price, PriceFeed, StoragePrice, StoragePriceFeed, + }; + use alloy_primitives::{B256, U256}; + + // Updated constants to use uppercase naming convention + const PRICE: i64 = 1000; + const CONF: u64 = 1000; + const EXPO: i32 = 1000; + + /// Generates a 256-bit hash filled with the byte value 30. + /// + /// # Returns + /// - `B256`: A 256-bit hash where each byte is set to 30. + fn generate_bytes() -> B256 { + B256::repeat_byte(30) + } + + #[motsu::test] + fn can_create_type_price() { + let price_result = Price { + price: PRICE, + conf: CONF, + expo: EXPO, + publish_time: U256::from(1000), + }; + assert_eq!(price_result.price, PRICE); + assert_eq!(price_result.conf, CONF); + assert_eq!(price_result.expo, EXPO); + assert_eq!(price_result.publish_time, U256::from(1000)); + } + + #[motsu::test] + fn can_create_type_price_feed() { + let id = generate_bytes(); + let price_result = Price { + price: PRICE, + conf: CONF, + expo: EXPO, + publish_time: U256::from(1000), + }; + let price_result_ema = Price { + price: PRICE, + conf: CONF, + expo: EXPO, + publish_time: U256::from(1000), + }; + let price_feed_result = + PriceFeed { id, price: price_result, ema_price: price_result_ema }; + assert_eq!(price_feed_result.price.price, PRICE); + assert_eq!(price_feed_result.price.conf, CONF); + assert_eq!(price_feed_result.price.expo, EXPO); + assert_eq!(price_feed_result.price.publish_time, U256::from(1000)); + assert_eq!(price_feed_result.ema_price.price, PRICE); + assert_eq!(price_feed_result.ema_price.conf, CONF); + assert_eq!(price_feed_result.ema_price.expo, EXPO); + assert_eq!(price_feed_result.ema_price.publish_time, U256::from(1000)); + } + + #[motsu::test] + fn can_create_type_storage_price() { + let price_result = Price { + price: PRICE, + conf: CONF, + expo: EXPO, + publish_time: U256::from(1000), + }; + let storage_price_result = StoragePrice::test_from_price(price_result); + let price_result = storage_price_result.to_price(); + assert_eq!(price_result.price, PRICE); + assert_eq!(price_result.conf, CONF); + assert_eq!(price_result.expo, EXPO); + assert_eq!(price_result.publish_time, U256::from(1000)); + } + + #[motsu::test] + fn can_create_type_storage_price_feed() { + let price_result = Price { + price: PRICE, + conf: CONF, + expo: EXPO, + publish_time: U256::from(1000), + }; + let price_result_ema = Price { + price: PRICE, + conf: CONF, + expo: EXPO, + publish_time: U256::from(1000), + }; + let price_feed_result = PriceFeed { + id: generate_bytes(), + price: price_result, + ema_price: price_result_ema, + }; + let storage_price_feed_result = + StoragePriceFeed::test_from_price_feed(price_feed_result); + let price_feed_result = storage_price_feed_result.to_price_feed(); + assert_eq!(price_feed_result.price.price, PRICE); + assert_eq!(price_feed_result.price.conf, CONF); + assert_eq!(price_feed_result.price.expo, EXPO); + assert_eq!(price_feed_result.price.publish_time, U256::from(1000)); + assert_eq!(price_feed_result.ema_price.price, PRICE); + assert_eq!(price_feed_result.ema_price.conf, CONF); + assert_eq!(price_feed_result.ema_price.expo, EXPO); + assert_eq!(price_feed_result.ema_price.publish_time, U256::from(1000)); + } +} diff --git a/target_chains/ethereum/sdk/stylus/contracts/src/utils/mod.rs b/target_chains/ethereum/sdk/stylus/contracts/src/utils/mod.rs new file mode 100644 index 0000000000..7ba19e172a --- /dev/null +++ b/target_chains/ethereum/sdk/stylus/contracts/src/utils/mod.rs @@ -0,0 +1,54 @@ +use { + alloc::vec::Vec, + alloy_sol_types::{SolCall, SolType}, + stylus_sdk::{ + alloy_primitives::Address, + call::{call, delegate_call}, + storage::TopLevelStorage, + }, +}; + +/// The revert message when failing to decode the data +/// returned by an external contract call +pub const CALL_RETDATA_DECODING_ERROR_MESSAGE: &[u8] = + b"error decoding retdata"; + +/// Maps an error returned from an external contract call to a `Vec`, +/// which is the expected return type of external contract methods. +pub fn map_call_error(e: stylus_sdk::call::Error) -> Vec { + match e { + stylus_sdk::call::Error::Revert(msg) => msg, + stylus_sdk::call::Error::AbiDecodingFailed(_) => { + CALL_RETDATA_DECODING_ERROR_MESSAGE.to_vec() + } + } +} + +/// Performs a `delegate call` to the given address, calling the function +/// defined as a `SolCall` with the given arguments. + +pub fn delegate_call_helper( + storage: &mut impl TopLevelStorage, + address: Address, + args: as SolType>::RustType, +) -> Result> { + let calldata = C::new(args).abi_encode(); + let res = unsafe { + delegate_call(storage, address, &calldata).map_err(map_call_error)? + }; + C::abi_decode_returns(&res, false /* validate */) + .map_err(|_| CALL_RETDATA_DECODING_ERROR_MESSAGE.to_vec()) +} + +/// Performs a `call` to the given address, calling the function +/// defined as a `SolCall` with the given arguments. +pub fn call_helper( + storage: &mut impl TopLevelStorage, + address: Address, + args: as SolType>::RustType, +) -> Result> { + let calldata = C::new(args).abi_encode(); + let res = call(storage, address, &calldata).map_err(map_call_error)?; + C::abi_decode_returns(&res, false /* validate */) + .map_err(|_| CALL_RETDATA_DECODING_ERROR_MESSAGE.to_vec()) +} diff --git a/target_chains/ethereum/sdk/stylus/examples/function-calls/Cargo.toml b/target_chains/ethereum/sdk/stylus/examples/function-calls/Cargo.toml new file mode 100644 index 0000000000..62159abfa7 --- /dev/null +++ b/target_chains/ethereum/sdk/stylus/examples/function-calls/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "function-calls-example" +edition.workspace = true +license.workspace = true +repository.workspace = true +publish = false +version.workspace = true + +[dependencies] +pyth-stylus.workspace = true +alloy-primitives = { workspace = true, features = ["tiny-keccak"] } +alloy-sol-types.workspace = true +stylus-sdk.workspace = true +mini-alloc.workspace = true +keccak-const.workspace = true + +[dev-dependencies] +alloy.workspace = true +eyre.workspace = true +tokio.workspace = true +e2e.workspace = true + +[lib] +crate-type = ["lib", "cdylib"] + +[features] +e2e = [] \ No newline at end of file diff --git a/target_chains/ethereum/sdk/stylus/examples/function-calls/src/constructor.sol b/target_chains/ethereum/sdk/stylus/examples/function-calls/src/constructor.sol new file mode 100644 index 0000000000..e8fcc679f2 --- /dev/null +++ b/target_chains/ethereum/sdk/stylus/examples/function-calls/src/constructor.sol @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +contract FunctionCallsExample { + address private pythAddress; + bytes32 private priceId; + + struct Price { + int64 price; + uint64 conf; + int32 expo; + uint256 publishTime; // Using uint256 as Solidity does not have a native uint type + } + + struct PriceFeed { + bytes32 id; + Price price; + Price emaPrice; + } + + // Storage variables for the Price and PriceFeed data + Price private price; + PriceFeed private priceFeed; + Price private ema_price; + PriceFeed private ema_priceFeed; + + constructor(address _pythAddress, bytes32 _priceId) { + pythAddress = _pythAddress; + priceId = _priceId; + price = Price(0, 0, 0, 0); + ema_price = Price(0, 0, 0, 0); + priceFeed = PriceFeed(_priceId, price, ema_price); + ema_priceFeed = PriceFeed(_priceId, ema_price, ema_price); + } +} diff --git a/target_chains/ethereum/sdk/stylus/examples/function-calls/src/lib.rs b/target_chains/ethereum/sdk/stylus/examples/function-calls/src/lib.rs new file mode 100644 index 0000000000..093d047b29 --- /dev/null +++ b/target_chains/ethereum/sdk/stylus/examples/function-calls/src/lib.rs @@ -0,0 +1,120 @@ +#![cfg_attr(not(test), no_std, no_main)] +extern crate alloc; + +use alloc::vec; +use alloc::vec::Vec; +use alloy_primitives::U256; +use alloy_sol_types::sol; +use pyth_stylus::pyth::{ + functions::{ + get_ema_price_no_older_than, get_ema_price_unsafe, + get_price_no_older_than, get_price_unsafe, get_update_fee, + get_valid_time_period, update_price_feeds, + update_price_feeds_if_necessary, + }, + mock::create_price_feed_update_data_list, + types::{StoragePrice, StoragePriceFeed}, +}; +use stylus_sdk::{ + console, + prelude::{entrypoint, public, sol_storage, SolidityError}, +}; + +sol_storage! { + #[entrypoint] + struct FunctionCallsExample { + address pyth_address; + bytes32 price_id; + StoragePrice price; + StoragePriceFeed price_feed; + StoragePrice ema_price; + StoragePriceFeed ema_price_feed; + } +} + +sol! { + + error ArraySizeNotMatch(); + + error CallFailed(); + +} + +#[derive(SolidityError)] +pub enum MultiCallErrors { + ArraySizeNotMatch(ArraySizeNotMatch), + + CallFailed(CallFailed), +} + +#[public] +impl FunctionCallsExample { + pub fn get_price_unsafe(&mut self) -> Result> { + let price_result = get_price_unsafe( + self, + self.pyth_address.get(), + self.price_id.get(), + )?; + self.price.set(price_result); + Ok(price_result.price) + } + + pub fn get_ema_price_unsafe(&mut self) -> Result> { + let price_result = get_ema_price_unsafe( + self, + self.pyth_address.get(), + self.price_id.get(), + )?; + Ok(price_result.price) + } + pub fn get_price_no_older_than(&mut self) -> Result> { + let price_result = get_price_no_older_than( + self, + self.pyth_address.get(), + self.price_id.get(), + U256::from(1000), + )?; + Ok(price_result.price) + } + + pub fn get_ema_price_no_older_than(&mut self) -> Result> { + let price_result = get_ema_price_no_older_than( + self, + self.pyth_address.get(), + self.price_id.get(), + U256::from(1000), + )?; + Ok(price_result.price) + } + + pub fn get_update_fee(&mut self) -> Result> { + let (data, _) = create_price_feed_update_data_list(); + let fee = get_update_fee(self, self.pyth_address.get(), data)?; + Ok(fee) + } + + pub fn get_valid_time_period(&mut self) -> Result> { + let time = get_valid_time_period(self, self.pyth_address.get())?; + Ok(time) + } + + #[payable] + pub fn update_price_feeds(&mut self) -> Result<(), Vec> { + let (data_bytes, _) = create_price_feed_update_data_list(); + let _ = update_price_feeds(self, self.pyth_address.get(), data_bytes)?; + Ok(()) + } + + #[payable] + pub fn update_price_feeds_if_necessary(&mut self) -> Result<(), Vec> { + let (data, ids) = create_price_feed_update_data_list(); + let _ = update_price_feeds_if_necessary( + self, + self.pyth_address.get(), + data, + ids, + vec![0, 0, 0], + )?; + Ok(()) + } +} diff --git a/target_chains/ethereum/sdk/stylus/examples/function-calls/tests/abi/mod.rs b/target_chains/ethereum/sdk/stylus/examples/function-calls/tests/abi/mod.rs new file mode 100644 index 0000000000..d7d4fcb067 --- /dev/null +++ b/target_chains/ethereum/sdk/stylus/examples/function-calls/tests/abi/mod.rs @@ -0,0 +1,16 @@ +#![allow(dead_code)] +use alloy::sol; + +sol!( + #[sol(rpc)] + contract FunctionCalls { + function getPriceUnsafe() external returns (int64 price); + function getEmaPriceUnsafe() external returns (int64 price); + function getPriceNoOlderThan() external returns (int64 price); + function getEmaPriceNoOlderThan() external returns (int64 price); + function getUpdateFee() external returns (uint256 fee); + function getValidTimePeriod() external returns (uint256 period); + function updatePriceFeeds() external payable; + function updatePriceFeedsIfNecessary() external payable; + } +); diff --git a/target_chains/ethereum/sdk/stylus/examples/function-calls/tests/function-calls.rs b/target_chains/ethereum/sdk/stylus/examples/function-calls/tests/function-calls.rs new file mode 100644 index 0000000000..4ccdc16e8c --- /dev/null +++ b/target_chains/ethereum/sdk/stylus/examples/function-calls/tests/function-calls.rs @@ -0,0 +1,173 @@ +#![cfg(feature = "e2e")] + +use std::assert_eq; + +use abi::FunctionCalls; +use alloy::{primitives::U256, sol}; +use alloy_primitives::{Address, FixedBytes}; +use e2e::{env, Account, ReceiptExt}; + +use crate::FunctionCallsExample::constructorCall; +use eyre::Result; + +mod abi; + +sol!("src/constructor.sol"); + +impl Default for constructorCall { + fn default() -> Self { + ctr("ETH", false) + } +} + +fn ctr(key_id: &str, invaid_pyth_address: bool) -> constructorCall { + let pyth_addr = if invaid_pyth_address { + "0xdC79c650B6560cBF15391C3F90A833a349735676".to_string() + } else { + env("MOCK_PYTH_ADDRESS").unwrap() + }; + let address_addr = Address::parse_checksummed(&pyth_addr, None).unwrap(); + let id = keccak_const::Keccak256::new() + .update(key_id.as_bytes()) + .finalize() + .to_vec(); + let price_id = FixedBytes::<32>::from_slice(&id); + constructorCall { _pythAddress: address_addr, _priceId: price_id } +} + +#[e2e::test] +async fn constructs(alice: Account) -> Result<()> { + // Deploy contract using `alice` account + let contract_addr = alice + .as_deployer() + .with_default_constructor::() + .deploy() + .await? + .address()?; + let _ = FunctionCalls::new(contract_addr, &alice.wallet); + Ok(()) +} + +#[e2e::test] +async fn error_provided_invaild_id(alice: Account) -> Result<()> { + let contract_addr = alice + .as_deployer() + .with_constructor(ctr("BALLON", false)) + .deploy() + .await? + .address()?; + let contract = FunctionCalls::new(contract_addr, &alice.wallet); + let result = contract.getPriceUnsafe().call().await; + assert!(result.is_err()); + Ok(()) +} + +#[e2e::test] +async fn error_provided_invaild_pyth_address(alice: Account) -> Result<()> { + let contract_addr = alice + .as_deployer() + .with_constructor(ctr("BALLON", true)) + .deploy() + .await? + .address()?; + let contract = FunctionCalls::new(contract_addr, &alice.wallet); + let result = contract.getPriceUnsafe().call().await; + assert!(result.is_err()); + Ok(()) +} + +#[e2e::test] +async fn can_get_price_unsafe(alice: Account) -> Result<()> { + // Deploy contract using `alice` account + let contract_addr = alice + .as_deployer() + .with_default_constructor::() // Assuming `constructorCall` is the constructor here + .deploy() + .await? + .address()?; + let contract = FunctionCalls::new(contract_addr, &alice.wallet); + let FunctionCalls::getPriceUnsafeReturn { price } = + contract.getPriceUnsafe().call().await?; + assert!(price > 0); + Ok(()) +} + +#[e2e::test] +async fn can_get_ema_price_unsafe(alice: Account) -> Result<()> { + // Deploy contract using `alice` account + let contract_addr = alice + .as_deployer() + .with_default_constructor::() // Assuming `constructorCall` is the constructor here + .deploy() + .await? + .address()?; + let contract = FunctionCalls::new(contract_addr, &alice.wallet); + let FunctionCalls::getEmaPriceUnsafeReturn { price } = + contract.getEmaPriceUnsafe().call().await?; + assert!(price > 0); + Ok(()) +} + +#[e2e::test] +async fn can_get_price_no_older_than(alice: Account) -> Result<()> { + // Deploy contract using `alice` account + let contract_addr = alice + .as_deployer() + .with_default_constructor::() // Assuming `constructorCall` is the constructor here + .deploy() + .await? + .address()?; + let contract = FunctionCalls::new(contract_addr, &alice.wallet); + let FunctionCalls::getPriceNoOlderThanReturn { price } = + contract.getPriceNoOlderThan().call().await?; + assert!(price > 0); + Ok(()) +} + +#[e2e::test] +async fn can_get_ema_price_no_older_than(alice: Account) -> Result<()> { + // Deploy contract using `alice` account + let contract_addr = alice + .as_deployer() + .with_default_constructor::() // Assuming `constructorCall` is the constructor here + .deploy() + .await? + .address()?; + let contract = FunctionCalls::new(contract_addr, &alice.wallet); + let FunctionCalls::getEmaPriceNoOlderThanReturn { price } = + contract.getEmaPriceNoOlderThan().call().await?; + assert!(price > 0); + Ok(()) +} + +#[e2e::test] +async fn can_get_fee(alice: Account) -> Result<()> { + // Deploy contract using `alice` account + let contract_addr = alice + .as_deployer() + .with_default_constructor::() // Assuming `constructorCall` is the constructor here + .deploy() + .await? + .address()?; + let contract = FunctionCalls::new(contract_addr, &alice.wallet); + let FunctionCalls::getUpdateFeeReturn { fee } = + contract.getUpdateFee().call().await?; + assert_eq!(fee, U256::from(300)); + Ok(()) +} + +#[e2e::test] +async fn can_get_period(alice: Account) -> Result<()> { + // Deploy contract using `alice` account + let contract_addr = alice + .as_deployer() + .with_default_constructor::() // Assuming `constructorCall` is the constructor here + .deploy() + .await? + .address()?; + let contract = FunctionCalls::new(contract_addr, &alice.wallet); + let FunctionCalls::getValidTimePeriodReturn { period } = + contract.getValidTimePeriod().call().await?; + assert_eq!(period, U256::from(100000)); + Ok(()) +} diff --git a/target_chains/ethereum/sdk/stylus/examples/proxy-calls/Cargo.toml b/target_chains/ethereum/sdk/stylus/examples/proxy-calls/Cargo.toml new file mode 100644 index 0000000000..791cb2bb07 --- /dev/null +++ b/target_chains/ethereum/sdk/stylus/examples/proxy-calls/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "proxy-calls-example" +edition.workspace = true +license.workspace = true +repository.workspace = true +publish = false +version.workspace = true + +[dependencies] +pyth-stylus.workspace = true +alloy-primitives = { workspace = true, features = ["tiny-keccak"] } +alloy-sol-types.workspace = true +stylus-sdk.workspace = true +mini-alloc.workspace = true +keccak-const.workspace = true + +[dev-dependencies] +alloy.workspace = true +eyre.workspace = true +tokio.workspace = true +e2e.workspace = true + +[lib] +crate-type = ["lib", "cdylib"] + +[features] +e2e = [] \ No newline at end of file diff --git a/target_chains/ethereum/sdk/stylus/examples/proxy-calls/src/constructor.sol b/target_chains/ethereum/sdk/stylus/examples/proxy-calls/src/constructor.sol new file mode 100644 index 0000000000..b1d1132989 --- /dev/null +++ b/target_chains/ethereum/sdk/stylus/examples/proxy-calls/src/constructor.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +contract ProxyCallsExample { + address private pythAddress; + + constructor(address _pythAddress) { + pythAddress = _pythAddress; + } +} diff --git a/target_chains/ethereum/sdk/stylus/examples/proxy-calls/src/lib.rs b/target_chains/ethereum/sdk/stylus/examples/proxy-calls/src/lib.rs new file mode 100644 index 0000000000..f0c7d7a4f4 --- /dev/null +++ b/target_chains/ethereum/sdk/stylus/examples/proxy-calls/src/lib.rs @@ -0,0 +1,17 @@ +#![cfg_attr(not(test), no_std, no_main)] +extern crate alloc; + +use pyth_stylus::pyth::pyth_contract::PythContract; +use stylus_sdk::prelude::{entrypoint, public, sol_storage}; + +sol_storage! { + #[entrypoint] + struct ProxyCallsExample { + #[borrow] + PythContract pyth + } +} + +#[public] +#[inherit(PythContract)] +impl ProxyCallsExample {} diff --git a/target_chains/ethereum/sdk/stylus/examples/proxy-calls/tests/abi/mod.rs b/target_chains/ethereum/sdk/stylus/examples/proxy-calls/tests/abi/mod.rs new file mode 100644 index 0000000000..e6d6f54107 --- /dev/null +++ b/target_chains/ethereum/sdk/stylus/examples/proxy-calls/tests/abi/mod.rs @@ -0,0 +1,16 @@ +#![allow(dead_code)] +use alloy::sol; + +sol!( + #[sol(rpc)] + contract ProxyCalls { + function getPriceUnsafe(bytes32 id) external returns (uint8[] price); + function getEmaPriceUnsafe(bytes32 id) external returns (uint8[] price); + function getPriceNoOlderThan(bytes32 id, uint age) external returns (uint8[] price); + function getEmaPriceNoOlderThan(bytes32 id, uint age) external returns (uint8[] price); + function getUpdateFee(bytes[] calldata updateData) external returns (uint256 fee); + function getValidTimePeriod() external returns (uint256 period); + function updatePriceFeeds(bytes[] calldata updateData) external payable; + function updatePriceFeedsIfNecessary(bytes[] calldata updateData, bytes32[] calldata priceIds, uint64[] calldata publishTimes) external payable; + } +); diff --git a/target_chains/ethereum/sdk/stylus/examples/proxy-calls/tests/proxy-calls.rs b/target_chains/ethereum/sdk/stylus/examples/proxy-calls/tests/proxy-calls.rs new file mode 100644 index 0000000000..3fa6d9218e --- /dev/null +++ b/target_chains/ethereum/sdk/stylus/examples/proxy-calls/tests/proxy-calls.rs @@ -0,0 +1,226 @@ +#![cfg(feature = "e2e")] + +use std::assert_eq; + +use abi::ProxyCalls; +use alloy::{primitives::U256, sol}; +use alloy_primitives::{Address, FixedBytes}; +use alloy_sol_types::SolValue; +use e2e::{env, Account, ReceiptExt}; + +use crate::ProxyCallsExample::constructorCall; +use eyre::Result; +use pyth_stylus::pyth::{ + mock::create_price_feed_update_data_list, types::Price, +}; + +mod abi; + +sol!("src/constructor.sol"); +// // ============================================================================ +// // Integration Tests: Proxy Calls +// // ============================================================================ + +impl Default for constructorCall { + fn default() -> Self { + ctr(false) + } +} + +fn generate_pyth_id_from_str(key_id: &str) -> FixedBytes<32> { + let id = keccak_const::Keccak256::new() + .update(key_id.as_bytes()) + .finalize() + .to_vec(); + let price_id = FixedBytes::<32>::from_slice(&id); + price_id +} + +fn ctr(invaid_pyth_address: bool) -> constructorCall { + let pyth_addr = if invaid_pyth_address { + "0xdC79c650B6560cBF15391C3F90A833a349735676".to_string() + } else { + env("MOCK_PYTH_ADDRESS").unwrap() + }; + let address_addr = Address::parse_checksummed(&pyth_addr, None).unwrap(); + constructorCall { _pythAddress: address_addr } +} + +#[e2e::test] +async fn constructs(alice: Account) -> Result<()> { + let contract_addr = alice + .as_deployer() + .with_default_constructor::() + .deploy() + .await? + .address()?; + + let contract = ProxyCalls::new(contract_addr, &alice.wallet); + let id = generate_pyth_id_from_str("ETH"); + contract.getPriceUnsafe(id).call().await?; + Ok(()) +} + +#[e2e::test] +async fn can_get_price_unsafe(alice: Account) -> Result<()> { + let contract_addr = alice + .as_deployer() + .with_default_constructor::() + .deploy() + .await? + .address()?; + let contract = ProxyCalls::new(contract_addr, &alice.wallet); + let id = generate_pyth_id_from_str("ETH"); + let ProxyCalls::getPriceUnsafeReturn { price } = + contract.getPriceUnsafe(id).call().await?; + let decoded_price = + Price::abi_decode(&price, false).expect("Failed to decode price"); + assert!(decoded_price.price > 0_i64); + assert!(decoded_price.conf > 0_u64); + assert!(decoded_price.expo > 0_i32); + assert!(decoded_price.publish_time > U256::from(0)); + Ok(()) +} + +#[e2e::test] +async fn error_provided_invaild_id_get_price_unsafe( + alice: Account, +) -> Result<()> { + let contract_addr = alice + .as_deployer() + .with_default_constructor::() + .deploy() + .await? + .address()?; + let contract = ProxyCalls::new(contract_addr, &alice.wallet); + let id = generate_pyth_id_from_str("BALLON"); + let price_result = contract.getPriceUnsafe(id).call().await; + assert!(price_result.is_err()); + Ok(()) +} + +#[e2e::test] +async fn can_get_ema_price_unsafe(alice: Account) -> Result<()> { + let contract_addr = alice + .as_deployer() + .with_default_constructor::() + .deploy() + .await? + .address()?; + let contract = ProxyCalls::new(contract_addr, &alice.wallet); + let id = generate_pyth_id_from_str("ETH"); + let ProxyCalls::getEmaPriceUnsafeReturn { price } = + contract.getEmaPriceUnsafe(id).call().await?; + let decoded_price = + Price::abi_decode(&price, false).expect("Failed to decode price"); + assert!(decoded_price.price > 0_i64); + assert!(decoded_price.conf > 0_u64); + assert!(decoded_price.expo > 0_i32); + assert!(decoded_price.publish_time > U256::from(0)); + Ok(()) +} + +#[e2e::test] +async fn error_provided_invaild_id_get_ema_price_unsafe( + alice: Account, +) -> Result<()> { + let contract_addr = alice + .as_deployer() + .with_default_constructor::() + .deploy() + .await? + .address()?; + let contract = ProxyCalls::new(contract_addr, &alice.wallet); + let id = generate_pyth_id_from_str("BALLON"); + let price_result = contract.getEmaPriceUnsafe(id).call().await; + assert!(price_result.is_err()); + Ok(()) +} + +#[e2e::test] +async fn can_get_price_no_older_than(alice: Account) -> Result<()> { + let contract_addr = alice + .as_deployer() + .with_default_constructor::() + .deploy() + .await? + .address()?; + let contract = ProxyCalls::new(contract_addr, &alice.wallet); + let id = generate_pyth_id_from_str("ETH"); + let ProxyCalls::getPriceNoOlderThanReturn { price } = + contract.getPriceNoOlderThan(id, U256::from(1000)).call().await?; + let decoded_price = + Price::abi_decode(&price, false).expect("Failed to decode price"); + assert!(decoded_price.price > 0_i64); + assert!(decoded_price.conf > 0_u64); + assert!(decoded_price.expo > 0_i32); + assert!(decoded_price.publish_time > U256::from(0)); + Ok(()) +} + +#[e2e::test] +async fn error_provided_invaild_id_get_price_no_older_than( + alice: Account, +) -> Result<()> { + let contract_addr = alice + .as_deployer() + .with_default_constructor::() + .deploy() + .await? + .address()?; + let contract = ProxyCalls::new(contract_addr, &alice.wallet); + let id = generate_pyth_id_from_str("BALLON"); + let price_result = + contract.getPriceNoOlderThan(id, U256::from(1000)).call().await; + assert!(price_result.is_err()); + Ok(()) +} + +#[e2e::test] +async fn error_provided_invaild_period_get_price_no_older_than( + alice: Account, +) -> Result<()> { + let contract_addr = alice + .as_deployer() + .with_default_constructor::() + .deploy() + .await? + .address()?; + let contract = ProxyCalls::new(contract_addr, &alice.wallet); + let id = generate_pyth_id_from_str("SOL"); + let price_result = + contract.getPriceNoOlderThan(id, U256::from(1)).call().await; + assert!(price_result.is_err()); + Ok(()) +} + +#[e2e::test] +async fn can_get_fee(alice: Account) -> Result<()> { + let contract_addr = alice + .as_deployer() + .with_default_constructor::() + .deploy() + .await? + .address()?; + let contract = ProxyCalls::new(contract_addr, &alice.wallet); + let (data, _id) = create_price_feed_update_data_list(); + let ProxyCalls::getUpdateFeeReturn { fee } = + contract.getUpdateFee(data).call().await?; + assert_eq!(fee, U256::from(300)); + Ok(()) +} + +#[e2e::test] +async fn can_get_valid_time_peroid(alice: Account) -> Result<()> { + let contract_addr = alice + .as_deployer() + .with_default_constructor::() + .deploy() + .await? + .address()?; + let contract = ProxyCalls::new(contract_addr, &alice.wallet); + let ProxyCalls::getValidTimePeriodReturn { period } = + contract.getValidTimePeriod().call().await?; + assert_eq!(period, U256::from(100000)); + Ok(()) +} diff --git a/target_chains/ethereum/sdk/stylus/pyth-mock-solidity/.gitignore b/target_chains/ethereum/sdk/stylus/pyth-mock-solidity/.gitignore new file mode 100644 index 0000000000..bb98a38c47 --- /dev/null +++ b/target_chains/ethereum/sdk/stylus/pyth-mock-solidity/.gitignore @@ -0,0 +1,15 @@ +# Compiler files +cache/ +out/ + +# Ignores development broadcast logs +!/broadcast +/broadcast/* +/broadcast/*/31337/ +/broadcast/**/dry-run/ + +# Docs +docs/ + +# Dotenv file +.env diff --git a/target_chains/ethereum/sdk/stylus/pyth-mock-solidity/README.md b/target_chains/ethereum/sdk/stylus/pyth-mock-solidity/README.md new file mode 100644 index 0000000000..a67dd3fc88 --- /dev/null +++ b/target_chains/ethereum/sdk/stylus/pyth-mock-solidity/README.md @@ -0,0 +1,67 @@ +## Foundry + +**The goal of the folder is to deploy a mock solidity pyth contract using the pyth sdk** + + +Foundry consists of: + +- **Forge**: Ethereum testing framework (like Truffle, Hardhat, and DappTools). +- **Cast**: Swiss army knife for interacting with EVM smart contracts, sending transactions, and getting chain data. +- **Anvil**: Local Ethereum node, akin to Ganache, Hardhat Network. +- **Chisel**: Fast, utilitarian, and verbose solidity REPL. + +## Documentation + +https://book.getfoundry.sh/ + +## Usage + +### Build + +```shell +$ forge build +``` + +### Test + +```shell +$ forge test +``` + +### Format + +```shell +$ forge fmt +``` + +### Gas Snapshots + +```shell +$ forge snapshot +``` + +### Anvil + +```shell +$ anvil +``` + +### Deploy + +```shell +$ forge script script/Counter.s.sol:CounterScript --rpc-url --private-key +``` + +### Cast + +```shell +$ cast +``` + +### Help + +```shell +$ forge --help +$ anvil --help +$ cast --help +``` diff --git a/target_chains/ethereum/sdk/stylus/pyth-mock-solidity/foundry.toml b/target_chains/ethereum/sdk/stylus/pyth-mock-solidity/foundry.toml new file mode 100644 index 0000000000..2bc70ba516 --- /dev/null +++ b/target_chains/ethereum/sdk/stylus/pyth-mock-solidity/foundry.toml @@ -0,0 +1,4 @@ +[profile.default] +src = "src" +out = "out" +libs = ["lib"] diff --git a/target_chains/ethereum/sdk/stylus/pyth-mock-solidity/lib/forge-std b/target_chains/ethereum/sdk/stylus/pyth-mock-solidity/lib/forge-std new file mode 160000 index 0000000000..1eea5bae12 --- /dev/null +++ b/target_chains/ethereum/sdk/stylus/pyth-mock-solidity/lib/forge-std @@ -0,0 +1 @@ +Subproject commit 1eea5bae12ae557d589f9f0f0edae2faa47cb262 diff --git a/target_chains/ethereum/sdk/stylus/pyth-mock-solidity/lib/openzeppelin-foundry-upgrades b/target_chains/ethereum/sdk/stylus/pyth-mock-solidity/lib/openzeppelin-foundry-upgrades new file mode 160000 index 0000000000..16e0ae21e0 --- /dev/null +++ b/target_chains/ethereum/sdk/stylus/pyth-mock-solidity/lib/openzeppelin-foundry-upgrades @@ -0,0 +1 @@ +Subproject commit 16e0ae21e0e39049f619f2396fa28c57fad07368 diff --git a/target_chains/ethereum/sdk/stylus/pyth-mock-solidity/package.json b/target_chains/ethereum/sdk/stylus/pyth-mock-solidity/package.json new file mode 100644 index 0000000000..c21961b5e7 --- /dev/null +++ b/target_chains/ethereum/sdk/stylus/pyth-mock-solidity/package.json @@ -0,0 +1,15 @@ +{ + "name": "pyth-mock-solidity", + "version": "1.0.0", + "description": "** Deploy mock solidity pyth contract using the pyth solidity sdk **", + "directories": { + "lib": "lib", + "test": "test" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "@pythnetwork/pyth-sdk-solidity": "^4.0.0" + } +} diff --git a/target_chains/ethereum/sdk/stylus/pyth-mock-solidity/remappings.txt b/target_chains/ethereum/sdk/stylus/pyth-mock-solidity/remappings.txt new file mode 100644 index 0000000000..939d22cd46 --- /dev/null +++ b/target_chains/ethereum/sdk/stylus/pyth-mock-solidity/remappings.txt @@ -0,0 +1 @@ +@pythnetwork/pyth-sdk-solidity/=node_modules/@pythnetwork/pyth-sdk-solidity \ No newline at end of file diff --git a/target_chains/ethereum/sdk/stylus/pyth-mock-solidity/script/MockPyth.s.sol b/target_chains/ethereum/sdk/stylus/pyth-mock-solidity/script/MockPyth.s.sol new file mode 100644 index 0000000000..bb2de23c4f --- /dev/null +++ b/target_chains/ethereum/sdk/stylus/pyth-mock-solidity/script/MockPyth.s.sol @@ -0,0 +1,83 @@ +/// SPDX-License-Identifier: Apache 2 +pragma solidity ^0.8.13; + +import {Script, console} from "forge-std/Script.sol"; +import {MockPythSample} from "../src/MockPyth.sol"; + +contract MockPythScript is Script { + uint randNonce = 0; + string[] tickers = ["ETH", "BTC", "USDT", "BNB", "SOL", "MATIC", "ADA", "DOT", "DOGE", "SHIB"]; + bytes[] priceData = new bytes[](tickers.length); + bytes32[] priceIds = new bytes32[](tickers.length); + MockPythSample pyth_contract; + + function setUp() public { + + } + + function run() public { + vm.startBroadcast(); + deploy(100000, 100); + _generateInitialData(); + console.log("Pyth contract address:", address(pyth_contract)); + uint update_cost = pyth_contract.getUpdateFee(priceData); + pyth_contract.updatePriceFeeds{value: update_cost}(priceData); + vm.stopBroadcast(); + } + + function deploy(uint validTimePeriod, uint singleUpdateFeeInWei) internal { + pyth_contract = new MockPythSample(validTimePeriod, singleUpdateFeeInWei); + } + + function _generateInitialData() internal { + for (uint i = 0; i < tickers.length; i++) { + priceIds[i] = keccak256(abi.encodePacked(tickers[i])); + + uint randomBase = uint(keccak256(abi.encodePacked(block.timestamp, priceIds[i], msg.sender))); + + int64 price = int64(uint64(_deriveRandom(randomBase, 1) % 10 )); + uint64 conf = uint64(_deriveRandom(randomBase, 2) % 10); + int32 expo = int32(uint32(_deriveRandom(randomBase, 3) % 40)); + int64 emaPrice = int64(uint64(_deriveRandom(randomBase, 4) % 10)); + uint64 emaConf = uint64(_deriveRandom(randomBase, 5) % 10); + priceData[i] = pyth_contract.createPriceFeedUpdateData( + priceIds[i], + price, + conf, + expo, + emaPrice, + emaConf, + uint64(block.timestamp), + 0 + ); + } + + } + + // Internal function to generate deterministic random numbers from a base seed + function _deriveRandom(uint base, uint salt) internal pure returns (uint) { + return uint(keccak256(abi.encodePacked(base, salt)) ) + 1; + } + + function uint2str(uint256 _i) internal pure returns (string memory str) { + if (_i == 0) { + return "0"; + } + uint256 j = _i; + uint256 length; + while (j != 0) + { + length++; + j /= 10; + } + bytes memory bstr = new bytes(length); + uint256 k = length; + j = _i; + while (j != 0) + { + bstr[--k] = bytes1(uint8(48 + j % 10)); + j /= 10; + } + str = string(bstr); + } +} diff --git a/target_chains/ethereum/sdk/stylus/pyth-mock-solidity/src/MockPyth.sol b/target_chains/ethereum/sdk/stylus/pyth-mock-solidity/src/MockPyth.sol new file mode 100644 index 0000000000..3b6632a8cf --- /dev/null +++ b/target_chains/ethereum/sdk/stylus/pyth-mock-solidity/src/MockPyth.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: Apache 2 +pragma solidity ^0.8.13; + +import "@pythnetwork/pyth-sdk-solidity/MockPyth.sol"; +import {console} from "forge-std/console.sol"; + +contract MockPythSample is MockPyth { + constructor( + uint validTimePeriod, uint singleUpdateFeeInWei + ) MockPyth(validTimePeriod, singleUpdateFeeInWei) { + + } +} \ No newline at end of file diff --git a/target_chains/ethereum/sdk/stylus/pyth-mock-solidity/test/MockPyth.t.sol b/target_chains/ethereum/sdk/stylus/pyth-mock-solidity/test/MockPyth.t.sol new file mode 100644 index 0000000000..85c47c5ffd --- /dev/null +++ b/target_chains/ethereum/sdk/stylus/pyth-mock-solidity/test/MockPyth.t.sol @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: Apache 2 +pragma solidity ^0.8.13; + +import {Test, console} from "forge-std/Test.sol"; + +contract MockPythTest is Test { + function setUp() public { + } +} diff --git a/target_chains/ethereum/sdk/stylus/rust-toolchain.toml b/target_chains/ethereum/sdk/stylus/rust-toolchain.toml new file mode 100644 index 0000000000..628740b12f --- /dev/null +++ b/target_chains/ethereum/sdk/stylus/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "1.79.0" diff --git a/target_chains/ethereum/sdk/stylus/scripts/bench.sh b/target_chains/ethereum/sdk/stylus/scripts/bench.sh new file mode 100755 index 0000000000..7a1f497f9b --- /dev/null +++ b/target_chains/ethereum/sdk/stylus/scripts/bench.sh @@ -0,0 +1,42 @@ +#!/bin/bash +# This Bash script deploys and benchmarks a mock Pyth contract in a simulated Ethereum environment. +# It sends an L2 transaction using a test node, captures the deployed contract address, and compiles Rust-based contracts to WebAssembly. +# Finally, it runs benchmarking to measure gas usage and performance. + +set -e + +MYDIR=$(realpath "$(dirname "$0")") +cd "$MYDIR" +cd .. + +export RPC_URL=http://localhost:8547 +export PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 +export WALLER_ADDRESS=0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 +ls +cd "nitro-testnode" +./test-node.bash script send-l2 --to address_$WALLER_ADDRESS --ethamount 0.1 + +cd .. +cd "pyth-mock-solidity" +deployed_to=$( + forge script ./script/MockPyth.s.sol:MockPythScript \ + --rpc-url "$RPC_URL" \ + --private-key "$PRIVATE_KEY" \ + --broadcast \ | grep -oP '(?<=Pyth contract address: )0x[a-fA-F0-9]{40}' | tail -n 1 +) + +export MOCK_PYTH_ADDRESS=$deployed_to +cd .. +# Output the captured address + +NIGHTLY_TOOLCHAIN=${NIGHTLY_TOOLCHAIN:-nightly-2024-01-01} +cargo +"$NIGHTLY_TOOLCHAIN" build --release --target wasm32-unknown-unknown -Z build-std=std,panic_abort -Z build-std-features=panic_immediate_abort + +# No need to compile benchmarks with `--release` +# since this only runs the benchmarking code and the contracts have already been compiled with `--release` +cargo run -p benches + +echo "NOTE: To measure non cached contract's gas usage correctly, + benchmarks should run on a clean instance of the nitro test node." +echo +echo "Finished running benches!" diff --git a/target_chains/ethereum/sdk/stylus/scripts/check-wasm.sh b/target_chains/ethereum/sdk/stylus/scripts/check-wasm.sh new file mode 100755 index 0000000000..2048d0a8e4 --- /dev/null +++ b/target_chains/ethereum/sdk/stylus/scripts/check-wasm.sh @@ -0,0 +1,35 @@ +#!/bin/bash +# This script compiles Rust contracts to WebAssembly and validates the .wasm binaries for correctness using cargo stylus check. +# It retrieves crate names from Cargo.toml files in the examples directory and ensures each compiled contract is valid + +set -e + +mydir=$(dirname "$0") +cd "$mydir" || exit +cd .. + +# Check contract wasm binary by crate name +check_wasm () { + local CONTRACT_CRATE_NAME=$1 + local CONTRACT_BIN_NAME="${CONTRACT_CRATE_NAME//-/_}.wasm" + + echo + echo "Checking contract $CONTRACT_CRATE_NAME" + cargo stylus check --wasm-file ./target/wasm32-unknown-unknown/release/"$CONTRACT_BIN_NAME" +} + +# Retrieve all alphanumeric contract's crate names in `./examples` directory. +get_example_crate_names () { + # shellcheck disable=SC2038 + # NOTE: optimistically relying on the 'name = ' string at Cargo.toml file + find ./examples -maxdepth 2 -type f -name "Cargo.toml" | xargs grep 'name = ' | grep -oE '".*"' | tr -d "'\"" +} + +NIGHTLY_TOOLCHAIN=${NIGHTLY_TOOLCHAIN:-nightly-2024-01-01} + +cargo +"$NIGHTLY_TOOLCHAIN" build --release --target wasm32-unknown-unknown -Z build-std=std,panic_abort -Z build-std-features=panic_immediate_abort + +for CRATE_NAME in $(get_example_crate_names) +do + check_wasm "$CRATE_NAME" +done diff --git a/target_chains/ethereum/sdk/stylus/scripts/deploy.sh b/target_chains/ethereum/sdk/stylus/scripts/deploy.sh new file mode 100755 index 0000000000..9f828aff0c --- /dev/null +++ b/target_chains/ethereum/sdk/stylus/scripts/deploy.sh @@ -0,0 +1,46 @@ +#!/bin/bash +# This script compiles Rust contracts to WebAssembly and deploys the .wasm binaries to a blockchain using `cargo stylus deploy`. +# It retrieves crate names from Cargo.toml files in the examples directory and automates the deployment process for each contract. + +set -e + +mydir=$(dirname "$0") +cd "$mydir" || exit +cd .. + +export RPC_URL=http://localhost:8547 +export PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 +export WALLER_ADDRESS=0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 + +cd "nitro-testnode" +./test-node.bash script send-l2 --to address_$WALLER_ADDRESS --ethamount 0.1 + + +cd .. +# Check contract wasm binary by crate name +deploy_wasm () { + local CONTRACT_CRATE_NAME=$1 + local CONTRACT_BIN_NAME="${CONTRACT_CRATE_NAME//-/_}.wasm" + + echo "deploy contract $CONTRACT_CRATE_NAME" + cargo stylus deploy --wasm-file ./target/wasm32-unknown-unknown/release/"$CONTRACT_BIN_NAME" \ + --endpoint $RPC_URL \ + --private-key $PRIVATE_KEY \ + --no-verify + } + +# Retrieve all alphanumeric contract's crate names in `./examples` directory. +get_example_crate_names () { + # shellcheck disable=SC2038 + # NOTE: optimistically relying on the 'name = ' string at Cargo.toml file + find ./examples -maxdepth 2 -type f -name "Cargo.toml" | xargs grep 'name = ' | grep -oE '".*"' | tr -d "'\"" +} + +NIGHTLY_TOOLCHAIN=${NIGHTLY_TOOLCHAIN:-nightly-2024-01-01} + +cargo +"$NIGHTLY_TOOLCHAIN" build --release --target wasm32-unknown-unknown -Z build-std=std,panic_abort -Z build-std-features=panic_immediate_abort + +for CRATE_NAME in $(get_example_crate_names) +do + deploy_wasm "$CRATE_NAME" +done diff --git a/target_chains/ethereum/sdk/stylus/scripts/e2e-tests.sh b/target_chains/ethereum/sdk/stylus/scripts/e2e-tests.sh new file mode 100755 index 0000000000..da5652544d --- /dev/null +++ b/target_chains/ethereum/sdk/stylus/scripts/e2e-tests.sh @@ -0,0 +1,37 @@ +#!/bin/bash +# This script automates the deployment and testing of Rust-based smart contracts. +# It sends L2 transactions, deploys the MockPyth contract using Forge, and captures its address. +# Finally, it compiles contracts to WebAssembly and runs end-to-end tests using a nightly Rust toolchain. + +MYDIR=$(realpath "$(dirname "$0")") +cd "$MYDIR" + +export RPC_URL=http://localhost:8547 +export PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 +export WALLER_ADDRESS=0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 + +cd .. +cd "nitro-testnode" +./test-node.bash script send-l2 --to address_$WALLER_ADDRESS --ethamount 0.1 + +cd .. +cd "pyth-mock-solidity" +deployed_to=$( + forge script ./script/MockPyth.s.sol:MockPythScript \ + --rpc-url "$RPC_URL" \ + --private-key "$PRIVATE_KEY" \ + --broadcast \ + | grep -oP '(?<=Pyth contract address: )0x[a-fA-F0-9]{40}' | tail -n 1 +) + +export MOCK_PYTH_ADDRESS=$deployed_to +cd .. + +# Run e2e tests +NIGHTLY_TOOLCHAIN=${NIGHTLY_TOOLCHAIN:-nightly-2024-01-01} +cargo +"$NIGHTLY_TOOLCHAIN" build --release --target wasm32-unknown-unknown -Z build-std=std,panic_abort -Z build-std-features=panic_immediate_abort + +export RPC_URL=http://localhost:8547 +# We should use stable here once nitro-testnode is updated and the contracts fit +# the size limit. Work tracked [here](https://github.com/OpenZeppelin/rust-contracts-stylus/issues/87) +cargo +"$NIGHTLY_TOOLCHAIN" test --features std,e2e --test "*" \ No newline at end of file diff --git a/target_chains/ethereum/sdk/stylus/scripts/nitro-testnode.sh b/target_chains/ethereum/sdk/stylus/scripts/nitro-testnode.sh new file mode 100755 index 0000000000..44556759d1 --- /dev/null +++ b/target_chains/ethereum/sdk/stylus/scripts/nitro-testnode.sh @@ -0,0 +1,70 @@ +#!/bin/bash +# This script manages the Nitro test node for deployment and testing purposes. +# It supports initializing the test node, running it in detached mode, or shutting it down. +# Options include cloning the Nitro test node repo if not present, and starting or stopping Docker containers as needed. + + +MYDIR=$(realpath "$(dirname "$0")") +cd "$MYDIR" || exit + +HAS_INIT=false +HAS_DETACH=false + +while [[ $# -gt 0 ]] +do + case "$1" in + -i|--init) + HAS_INIT=true + shift + ;; + -d|--detach) + HAS_DETACH=true + shift + ;; + -q|--quit) + NITRO_CONTAINERS=$(docker container ls -q --filter name=nitro-testnode) + + if [ -z "$NITRO_CONTAINERS" ]; then + echo "No nitro-testnode containers running" + else + docker container stop $NITRO_CONTAINERS || exit + fi + + exit 0 + ;; + *) + echo "OPTIONS:" + echo "-i|--init: clone repo and init nitro test node" + echo "-d|--detach: setup nitro test node in detached mode" + echo "-q|--quit: shutdown nitro test node docker containers" + exit 0 + ;; + esac +done + +TEST_NODE_DIR="$MYDIR/../nitro-testnode" +if [ ! -d "$TEST_NODE_DIR" ]; then + HAS_INIT=true +fi + +if $HAS_INIT +then + cd "$MYDIR" || exit + cd .. + + git clone --recurse-submodules https://github.com/OffchainLabs/nitro-testnode.git + cd ./nitro-testnode || exit + git pull origin release --recurse-submodules + git checkout d4244cd5c2cb56ca3d11c23478ef9642f8ebf472 || exit + + ./test-node.bash --no-run --init || exit +fi + + +cd "$TEST_NODE_DIR" || exit +if $HAS_DETACH +then + ./test-node.bash --detach +else + ./test-node.bash +fi