diff --git a/.config/nextest.toml b/.config/nextest.toml new file mode 100644 index 0000000..7053c63 --- /dev/null +++ b/.config/nextest.toml @@ -0,0 +1,8 @@ +[test-groups] +# Limit concurrency for tests that spin up Docker containers (Kafka + MinIO) +# to avoid resource contention causing container startup failures. +container-tests = { max-threads = 4 } + +[[profile.default.overrides]] +filter = 'binary_id(audit::s3_test) | binary_id(audit::integration_tests)' +test-group = 'container-tests' diff --git a/.env.example b/.env.example index 20fe76e..a53a4c6 100644 --- a/.env.example +++ b/.env.example @@ -3,4 +3,48 @@ GETH_MEMPOOL_ENDPOINT=http://localhost:8546 RETH_MEMPOOL_ENDPOINT=http://localhost:8547 # Service selection for generic Docker commands -SERVICE=mempool-rebroadcaster \ No newline at end of file +SERVICE=mempool-rebroadcaster + +# Ingress +TIPS_INGRESS_ADDRESS=0.0.0.0 +TIPS_INGRESS_PORT=8080 +TIPS_INGRESS_RPC_MEMPOOL=http://localhost:2222 +TIPS_INGRESS_TX_SUBMISSION_METHOD=mempool +TIPS_INGRESS_KAFKA_INGRESS_PROPERTIES_FILE=/app/docker/ingress-bundles-kafka-properties +TIPS_INGRESS_KAFKA_INGRESS_TOPIC=tips-ingress +TIPS_INGRESS_KAFKA_AUDIT_PROPERTIES_FILE=/app/docker/ingress-audit-kafka-properties +TIPS_INGRESS_KAFKA_AUDIT_TOPIC=tips-audit +TIPS_INGRESS_KAFKA_USER_OPERATION_CONSUMER_PROPERTIES_FILE=/app/docker/ingress-user-operation-consumer-kafka-properties +TIPS_INGRESS_LOG_LEVEL=info +TIPS_INGRESS_LOG_FORMAT=pretty +TIPS_INGRESS_SEND_TRANSACTION_DEFAULT_LIFETIME_SECONDS=10800 +TIPS_INGRESS_RPC_SIMULATION=http://localhost:8549 +TIPS_INGRESS_METRICS_ADDR=0.0.0.0:9002 +TIPS_INGRESS_HEALTH_CHECK_ADDR=0.0.0.0:8081 +TIPS_INGRESS_BLOCK_TIME_MILLISECONDS=2000 +TIPS_INGRESS_METER_BUNDLE_TIMEOUT_MS=2000 +TIPS_INGRESS_MAX_BUFFERED_METER_BUNDLE_RESPONSES=100 +TIPS_INGRESS_BUILDER_RPCS=http://localhost:2222,http://localhost:2222,http://localhost:2222 +TIPS_INGRESS_BACKRUN_ENABLED=true + +# Audit service configuration +TIPS_AUDIT_KAFKA_PROPERTIES_FILE=/app/docker/audit-kafka-properties +TIPS_AUDIT_KAFKA_TOPIC=tips-audit +TIPS_AUDIT_LOG_LEVEL=info +TIPS_AUDIT_LOG_FORMAT=pretty +TIPS_AUDIT_S3_BUCKET=tips +TIPS_AUDIT_S3_CONFIG_TYPE=manual +TIPS_AUDIT_S3_ENDPOINT=http://localhost:7000 +TIPS_AUDIT_S3_REGION=us-east-1 +TIPS_AUDIT_S3_ACCESS_KEY_ID=minioadmin +TIPS_AUDIT_S3_SECRET_ACCESS_KEY=minioadmin + +# TIPS UI +NEXT_PUBLIC_BLOCK_EXPLORER_URL=https://base.blockscout.com +TIPS_UI_RPC_URL=http://localhost:8549 +TIPS_UI_AWS_REGION=us-east-1 +TIPS_UI_S3_BUCKET_NAME=tips +TIPS_UI_S3_CONFIG_TYPE=manual +TIPS_UI_S3_ENDPOINT=http://localhost:7000 +TIPS_UI_S3_ACCESS_KEY_ID=minioadmin +TIPS_UI_S3_SECRET_ACCESS_KEY=minioadmin \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6c1cf89..d4c83ac 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -178,14 +178,12 @@ jobs: egress-policy: audit - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - - uses: dtolnay/rust-toolchain@0c3131df9e5407c0c36352032d04af846dbe0fb7 # nightly - with: - components: rustfmt + - uses: dtolnay/rust-toolchain@4305c38b25d97ef35a8ad1f985ccf2d2242004f2 # stable - uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2.8.2 with: cache-on-failure: true add-rust-environment-hash-key: "false" - key: nightly-${{ hashFiles('Cargo.lock') }} + key: stable-${{ hashFiles('Cargo.lock') }} - name: Install just uses: extractions/setup-just@e33e0265a09d6d736e2ee1e0eb685ef1de4669ff # v3 - - run: just check-format + - run: just check-deny diff --git a/.github/workflows/ui.yml b/.github/workflows/ui.yml new file mode 100644 index 0000000..6587ce8 --- /dev/null +++ b/.github/workflows/ui.yml @@ -0,0 +1,109 @@ +name: UI +permissions: + contents: read + +on: + push: + branches: [ master ] + paths: ['ui/**'] + pull_request: + paths: ['ui/**'] + +jobs: + changes: + name: Detect Changes + runs-on: ubuntu-latest + outputs: + projects: ${{ steps.filter.outputs.projects }} + steps: + - name: Harden the runner (Audit all outbound calls) + uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1 + with: + egress-policy: audit + + - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 + - uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2 + id: paths + with: + filters: | + tips: + - 'ui/tips/**' + - id: filter + run: | + projects='[]' + if [ "${{ steps.paths.outputs.tips }}" == "true" ]; then + projects=$(echo "$projects" | jq -c '. + ["tips"]') + fi + echo "projects=$projects" >> $GITHUB_OUTPUT + + lint: + name: Lint (${{ matrix.project }}) + needs: changes + if: ${{ needs.changes.outputs.projects != '[]' }} + runs-on: ubuntu-latest + strategy: + matrix: + project: ${{ fromJson(needs.changes.outputs.projects) }} + steps: + - name: Harden the runner (Audit all outbound calls) + uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1 + with: + egress-policy: audit + + - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version: '20' + cache: 'yarn' + cache-dependency-path: ui/${{ matrix.project }}/yarn.lock + - run: cp .env.example ui/${{ matrix.project }}/.env + - run: cd ui/${{ matrix.project }} && yarn install + - run: cd ui/${{ matrix.project }} && yarn lint + + type-check: + name: Type Check (${{ matrix.project }}) + needs: changes + if: ${{ needs.changes.outputs.projects != '[]' }} + runs-on: ubuntu-latest + strategy: + matrix: + project: ${{ fromJson(needs.changes.outputs.projects) }} + steps: + - name: Harden the runner (Audit all outbound calls) + uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1 + with: + egress-policy: audit + + - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version: '20' + cache: 'yarn' + cache-dependency-path: ui/${{ matrix.project }}/yarn.lock + - run: cp .env.example ui/${{ matrix.project }}/.env + - run: cd ui/${{ matrix.project }} && yarn install + - run: cd ui/${{ matrix.project }} && npx tsc --noEmit + + build: + name: Build (${{ matrix.project }}) + needs: changes + if: ${{ needs.changes.outputs.projects != '[]' }} + runs-on: ubuntu-latest + strategy: + matrix: + project: ${{ fromJson(needs.changes.outputs.projects) }} + steps: + - name: Harden the runner (Audit all outbound calls) + uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1 + with: + egress-policy: audit + + - uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0 + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version: '20' + cache: 'yarn' + cache-dependency-path: ui/${{ matrix.project }}/yarn.lock + - run: cp .env.example ui/${{ matrix.project }}/.env + - run: cd ui/${{ matrix.project }} && yarn install + - run: cd ui/${{ matrix.project }} && yarn build \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index ccf4f1d..accacad 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,6 +8,19 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "getrandom 0.3.4", + "once_cell", + "version_check", + "zerocopy", +] + [[package]] name = "aho-corasick" version = "1.1.4" @@ -45,15 +58,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90f374d3c6d729268bbe2d0e0ff992bb97898b2df756691a62ee1d5f0506bc39" dependencies = [ "alloy-primitives", + "alloy-rlp", "num_enum", + "serde", "strum 0.27.2", ] [[package]] name = "alloy-consensus" -version = "1.6.1" +version = "1.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86debde32d8dbb0ab29e7cc75ae1a98688ac7a4c9da54b3a9b14593b9b3c46d3" +checksum = "4e4ff99651d46cef43767b5e8262ea228cd05287409ccb0c947cc25e70a952f9" dependencies = [ "alloy-eips", "alloy-primitives", @@ -69,18 +84,18 @@ dependencies = [ "k256", "once_cell", "rand 0.8.5", - "secp256k1", + "secp256k1 0.30.0", "serde", "serde_json", "serde_with", - "thiserror", + "thiserror 2.0.18", ] [[package]] name = "alloy-consensus-any" -version = "1.6.1" +version = "1.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d6cb2e7efd385b333f5a77b71baaa2605f7e22f1d583f2879543b54cbce777c" +checksum = "1a0701b0eda8051a2398591113e7862f807ccdd3315d0b441f06c2a0865a379b" dependencies = [ "alloy-consensus", "alloy-eips", @@ -92,9 +107,9 @@ dependencies = [ [[package]] name = "alloy-contract" -version = "1.6.1" +version = "1.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "668859fcdb42eee289de22a9d01758c910955bb6ecda675b97276f99ce2e16b0" +checksum = "f3c83c7a3c4e1151e8cac383d0a67ddf358f37e5ea51c95a1283d897c9de0a5a" dependencies = [ "alloy-consensus", "alloy-dyn-abi", @@ -109,14 +124,14 @@ dependencies = [ "futures", "futures-util", "serde_json", - "thiserror", + "thiserror 2.0.18", ] [[package]] name = "alloy-dyn-abi" -version = "1.5.4" +version = "1.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14ff5ee5f27aa305bda825c735f686ad71bb65508158f059f513895abe69b8c3" +checksum = "e6ab1b2f1b48a7e6b3597cb2afae04f93879fb69d71e39736b5663d7366b23f2" dependencies = [ "alloy-json-abi", "alloy-primitives", @@ -138,7 +153,7 @@ dependencies = [ "alloy-rlp", "crc", "serde", - "thiserror", + "thiserror 2.0.18", ] [[package]] @@ -162,8 +177,9 @@ dependencies = [ "alloy-primitives", "alloy-rlp", "borsh", + "k256", "serde", - "thiserror", + "thiserror 2.0.18", ] [[package]] @@ -180,9 +196,9 @@ dependencies = [ [[package]] name = "alloy-eips" -version = "1.6.1" +version = "1.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be47bf1b91674a5f394b9ed3c691d764fb58ba43937f1371550ff4bc8e59c295" +checksum = "def1626eea28d48c6cc0a6f16f34d4af0001906e4f889df6c660b39c86fd044d" dependencies = [ "alloy-eip2124", "alloy-eip2930", @@ -196,17 +212,69 @@ dependencies = [ "c-kzg", "derive_more", "either", + "ethereum_ssz", + "ethereum_ssz_derive", "serde", "serde_with", "sha2", - "thiserror", + "thiserror 2.0.18", +] + +[[package]] +name = "alloy-evm" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b99ba7b74a87176f31ee1cd26768f7155b0eeff61ed925f59b13085ffe5f891" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-hardforks", + "alloy-op-hardforks", + "alloy-primitives", + "alloy-rpc-types-engine", + "alloy-rpc-types-eth", + "alloy-sol-types", + "auto_impl", + "derive_more", + "op-alloy", + "op-revm", + "revm", + "thiserror 2.0.18", +] + +[[package]] +name = "alloy-genesis" +version = "1.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55d9d1aba3f914f0e8db9e4616ae37f3d811426d95bdccf44e47d0605ab202f6" +dependencies = [ + "alloy-eips", + "alloy-primitives", + "alloy-serde", + "alloy-trie", + "borsh", + "serde", + "serde_with", +] + +[[package]] +name = "alloy-hardforks" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83ba208044232d14d4adbfa77e57d6329f51bc1acc21f5667bb7db72d88a0831" +dependencies = [ + "alloy-chains", + "alloy-eip2124", + "alloy-primitives", + "auto_impl", + "dyn-clone", ] [[package]] name = "alloy-json-abi" -version = "1.5.4" +version = "1.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8708475665cc00e081c085886e68eada2f64cfa08fc668213a9231655093d4de" +checksum = "1e414aa37b335ad2acb78a95814c59d137d53139b412f87aed1e10e2d862cd49" dependencies = [ "alloy-primitives", "alloy-sol-type-parser", @@ -216,24 +284,24 @@ dependencies = [ [[package]] name = "alloy-json-rpc" -version = "1.6.1" +version = "1.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a24c81a56d684f525cd1c012619815ad3a1dd13b0238f069356795d84647d3c" +checksum = "e57586581f2008933241d16c3e3f633168b3a5d2738c5c42ea5246ec5e0ef17a" dependencies = [ "alloy-primitives", "alloy-sol-types", - "http", + "http 1.4.0", "serde", "serde_json", - "thiserror", + "thiserror 2.0.18", "tracing", ] [[package]] name = "alloy-network" -version = "1.6.1" +version = "1.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "786c5b3ad530eaf43cda450f973fe7fb1c127b4c8990adf66709dafca25e3f6f" +checksum = "3b36c2a0ed74e48851f78415ca5b465211bd678891ba11e88fee09eac534bab1" dependencies = [ "alloy-consensus", "alloy-consensus-any", @@ -252,14 +320,14 @@ dependencies = [ "futures-utils-wasm", "serde", "serde_json", - "thiserror", + "thiserror 2.0.18", ] [[package]] name = "alloy-network-primitives" -version = "1.6.1" +version = "1.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1ed40adf21ae4be786ef5eb62db9c692f6a30f86d34452ca3f849d6390ce319" +checksum = "636c8051da58802e757b76c3b65af610b95799f72423dc955737dec73de234fd" dependencies = [ "alloy-consensus", "alloy-eips", @@ -268,11 +336,41 @@ dependencies = [ "serde", ] +[[package]] +name = "alloy-op-evm" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "646a01ebc9778ee08bcc33cfa6714efc548f94e53de1aff6b34d9da55a2e5d41" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-evm", + "alloy-op-hardforks", + "alloy-primitives", + "auto_impl", + "op-alloy", + "op-revm", + "revm", + "thiserror 2.0.18", +] + +[[package]] +name = "alloy-op-hardforks" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6472c610150c4c4c15be9e1b964c9b78068f933bda25fb9cdf09b9ac2bb66f36" +dependencies = [ + "alloy-chains", + "alloy-hardforks", + "alloy-primitives", + "auto_impl", +] + [[package]] name = "alloy-primitives" -version = "1.5.4" +version = "1.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b88cf92ed20685979ed1d8472422f0c6c2d010cec77caf63aaa7669cc1a7bc2" +checksum = "66b1483f8c2562bf35f0270b697d5b5fe8170464e935bd855a4c5eaf6f89b354" dependencies = [ "alloy-rlp", "bytes", @@ -280,6 +378,7 @@ dependencies = [ "const-hex", "derive_more", "foldhash 0.2.0", + "getrandom 0.4.1", "hashbrown 0.16.1", "indexmap 2.13.0", "itoa", @@ -297,9 +396,9 @@ dependencies = [ [[package]] name = "alloy-provider" -version = "1.6.1" +version = "1.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3ca4c15818be7ac86208aff3a91b951d14c24e1426e66624e75f2215ba5e2cc" +checksum = "b3dd56e2eafe8b1803e325867ac2c8a4c73c9fb5f341ffd8347f9344458c5922" dependencies = [ "alloy-chains", "alloy-consensus", @@ -330,7 +429,7 @@ dependencies = [ "reqwest", "serde", "serde_json", - "thiserror", + "thiserror 2.0.18", "tokio", "tracing", "url", @@ -339,9 +438,9 @@ dependencies = [ [[package]] name = "alloy-pubsub" -version = "1.6.1" +version = "1.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9eb9c9371738ac47f589e40aae6e418cb5f7436ad25b87575a7f94a60ccf43b" +checksum = "6eebf54983d4fccea08053c218ee5c288adf2e660095a243d0532a8070b43955" dependencies = [ "alloy-json-rpc", "alloy-primitives", @@ -378,14 +477,14 @@ checksum = "ce8849c74c9ca0f5a03da1c865e3eb6f768df816e67dd3721a398a8a7e398011" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.115", ] [[package]] name = "alloy-rpc-client" -version = "1.6.1" +version = "1.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abe0addad5b8197e851062b49dc47157444bced173b601d91e3f9b561a060a50" +checksum = "91577235d341a1bdbee30a463655d08504408a4d51e9f72edbfc5a622829f402" dependencies = [ "alloy-json-rpc", "alloy-primitives", @@ -408,21 +507,34 @@ dependencies = [ [[package]] name = "alloy-rpc-types" -version = "1.6.1" +version = "1.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74d17d4645a717f0527e491f44f6f7a75c221b9c00ccf79ddba2d26c8e0df4c3" +checksum = "79cff039bf01a17d76c0aace3a3a773d5f895eb4c68baaae729ec9da9e86c99c" dependencies = [ "alloy-primitives", + "alloy-rpc-types-eth", "alloy-rpc-types-txpool", "alloy-serde", "serde", ] +[[package]] +name = "alloy-rpc-types-admin" +version = "1.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "564afceae126df73b95f78c81eb46e2ef689a45ace0fcdaf5c9a178693a5ccca" +dependencies = [ + "alloy-genesis", + "alloy-primitives", + "serde", + "serde_json", +] + [[package]] name = "alloy-rpc-types-any" -version = "1.6.1" +version = "1.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0e98aabb013a71a4b67b52825f7b503e5bb6057fb3b7b2290d514b0b0574b57" +checksum = "73234a141ecce14e2989748c04fcac23deee67a445e2c4c167cfb42d4dacd1b6" dependencies = [ "alloy-consensus-any", "alloy-rpc-types-eth", @@ -431,9 +543,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-engine" -version = "1.6.1" +version = "1.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddc871ae69688e358cf242a6a7ee6b6e0476a03fd0256434c68daedaec086ec4" +checksum = "10620d600cc46538f613c561ac9a923843c6c74c61f054828dcdb8dd18c72ec4" dependencies = [ "alloy-consensus", "alloy-eips", @@ -441,6 +553,8 @@ dependencies = [ "alloy-rlp", "alloy-serde", "derive_more", + "ethereum_ssz", + "ethereum_ssz_derive", "jsonwebtoken", "rand 0.8.5", "serde", @@ -449,9 +563,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-eth" -version = "1.6.1" +version = "1.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5899af8417dcf89f40f88fa3bdb2f3f172605d8e167234311ee34811bbfdb0bf" +checksum = "010e101dbebe0c678248907a2545b574a87d078d82c2f6f5d0e8e7c9a6149a10" dependencies = [ "alloy-consensus", "alloy-consensus-any", @@ -465,14 +579,28 @@ dependencies = [ "serde", "serde_json", "serde_with", - "thiserror", + "thiserror 2.0.18", +] + +[[package]] +name = "alloy-rpc-types-trace" +version = "1.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be096f74d85e1f927580b398bf7bc5b4aa62326f149680ec0867e3c040c9aced" +dependencies = [ + "alloy-primitives", + "alloy-rpc-types-eth", + "alloy-serde", + "serde", + "serde_json", + "thiserror 2.0.18", ] [[package]] name = "alloy-rpc-types-txpool" -version = "1.6.1" +version = "1.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a8074654c0292783d504bfa1f2691a69f420154ee9a7883f9212eaf611e60cd" +checksum = "14ab75189fbc29c5dd6f0bc1529bccef7b00773b458763f4d9d81a77ae4a1a2d" dependencies = [ "alloy-primitives", "alloy-rpc-types-eth", @@ -482,9 +610,9 @@ dependencies = [ [[package]] name = "alloy-serde" -version = "1.6.1" +version = "1.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "feb73325ee881e42972a5a7bc85250f6af89f92c6ad1222285f74384a203abeb" +checksum = "9e6d631f8b975229361d8af7b2c749af31c73b3cf1352f90e144ddb06227105e" dependencies = [ "alloy-primitives", "serde", @@ -493,9 +621,9 @@ dependencies = [ [[package]] name = "alloy-signer" -version = "1.6.1" +version = "1.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bea4c8f30eddb11d7ab56e83e49c814655daa78ca708df26c300c10d0189cbc" +checksum = "97f40010b5e8f79b70bf163b38cd15f529b18ca88c4427c0e43441ee54e4ed82" dependencies = [ "alloy-primitives", "async-trait", @@ -503,28 +631,44 @@ dependencies = [ "either", "elliptic-curve", "k256", - "thiserror", + "thiserror 2.0.18", +] + +[[package]] +name = "alloy-signer-local" +version = "1.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c4ec1cc27473819399a3f0da83bc1cef0ceaac8c1c93997696e46dc74377a58" +dependencies = [ + "alloy-consensus", + "alloy-network", + "alloy-primitives", + "alloy-signer", + "async-trait", + "k256", + "rand 0.8.5", + "thiserror 2.0.18", ] [[package]] name = "alloy-sol-macro" -version = "1.5.4" +version = "1.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5fa1ca7e617c634d2bd9fa71f9ec8e47c07106e248b9fcbd3eaddc13cabd625" +checksum = "2c4b64c8146291f750c3f391dff2dd40cf896f7e2b253417a31e342aa7265baa" dependencies = [ "alloy-sol-macro-expander", "alloy-sol-macro-input", "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.115", ] [[package]] name = "alloy-sol-macro-expander" -version = "1.5.4" +version = "1.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27c00c0c3a75150a9dc7c8c679ca21853a137888b4e1c5569f92d7e2b15b5102" +checksum = "d9df903674682f9bae8d43fdea535ab48df2d6a8cb5104ca29c58ada22ef67b3" dependencies = [ "alloy-sol-macro-input", "const-hex", @@ -534,15 +678,15 @@ dependencies = [ "proc-macro2", "quote", "sha3", - "syn 2.0.114", + "syn 2.0.115", "syn-solidity", ] [[package]] name = "alloy-sol-macro-input" -version = "1.5.4" +version = "1.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "297db260eb4d67c105f68d6ba11b8874eec681caec5505eab8fbebee97f790bc" +checksum = "737b8a959f527a86e07c44656db237024a32ae9b97d449f788262a547e8aa136" dependencies = [ "const-hex", "dunce", @@ -550,15 +694,15 @@ dependencies = [ "macro-string", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.115", "syn-solidity", ] [[package]] name = "alloy-sol-type-parser" -version = "1.5.4" +version = "1.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94b91b13181d3bcd23680fd29d7bc861d1f33fbe90fdd0af67162434aeba902d" +checksum = "b28e6e86c6d2db52654b65a5a76b4f57eae5a32a7f0aa2222d1dbdb74e2cb8e0" dependencies = [ "serde", "winnow", @@ -566,9 +710,9 @@ dependencies = [ [[package]] name = "alloy-sol-types" -version = "1.5.4" +version = "1.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc442cc2a75207b708d481314098a0f8b6f7b58e3148dd8d8cc7407b0d6f9385" +checksum = "fdf7effe4ab0a4f52c865959f790036e61a7983f68b13b75d7fbcedf20b753ce" dependencies = [ "alloy-json-abi", "alloy-primitives", @@ -578,20 +722,20 @@ dependencies = [ [[package]] name = "alloy-transport" -version = "1.6.1" +version = "1.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b321f506bd67a434aae8e8a7dfe5373bf66137c149a5f09c9e7dfb0ca43d7c91" +checksum = "a03bb3f02b9a7ab23dacd1822fa7f69aa5c8eefcdcf57fad085e0b8d76fb4334" dependencies = [ "alloy-json-rpc", "auto_impl", - "base64", + "base64 0.22.1", "derive_more", "futures", "futures-utils-wasm", "parking_lot", "serde", "serde_json", - "thiserror", + "thiserror 2.0.18", "tokio", "tower", "tracing", @@ -601,12 +745,13 @@ dependencies = [ [[package]] name = "alloy-transport-http" -version = "1.6.1" +version = "1.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30bf12879a20e1261cd39c3b101856f52d18886907a826e102538897f0d2b66e" +checksum = "5ce599598ef8ebe067f3627509358d9faaa1ef94f77f834a7783cd44209ef55c" dependencies = [ "alloy-json-rpc", "alloy-transport", + "itertools 0.14.0", "opentelemetry", "opentelemetry-http", "reqwest", @@ -619,14 +764,14 @@ dependencies = [ [[package]] name = "alloy-transport-ws" -version = "1.6.1" +version = "1.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "527a0d9c8bbc5c3215b03ad465d4ae8775384ff5faec7c41f033f087c851a9f9" +checksum = "5ed38ea573c6658e0c2745af9d1f1773b1ed83aa59fbd9c286358ad469c3233a" dependencies = [ "alloy-pubsub", "alloy-transport", "futures", - "http", + "http 1.4.0", "serde_json", "tokio", "tokio-tungstenite", @@ -647,20 +792,20 @@ dependencies = [ "nybbles", "serde", "smallvec", - "thiserror", + "thiserror 2.0.18", "tracing", ] [[package]] name = "alloy-tx-macros" -version = "1.6.1" +version = "1.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a91d6b4c2f6574fdbcb1611e460455c326667cf5b805c6bd1640dad8e8ee4d2" +checksum = "397406cf04b11ca2a48e6f81804c70af3f40a36abf648e11dc7416043eb0834d" dependencies = [ "darling 0.21.3", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.115", ] [[package]] @@ -728,6 +873,20 @@ version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f0e0fee31ef5ed1ba1316088939cea399010ed7731dba877ed44aeb407a75ea" +[[package]] +name = "aquamarine" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f50776554130342de4836ba542aa85a4ddb361690d7e8df13774d7284c3d5c2" +dependencies = [ + "include_dir", + "itertools 0.10.5", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.115", +] + [[package]] name = "arboard" version = "3.6.1" @@ -748,6 +907,51 @@ dependencies = [ "x11rb", ] +[[package]] +name = "ark-bls12-381" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3df4dcc01ff89867cd86b0da835f23c3f02738353aaee7dde7495af71363b8d5" +dependencies = [ + "ark-ec", + "ark-ff 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", +] + +[[package]] +name = "ark-bn254" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d69eab57e8d2663efa5c63135b2af4f396d66424f88954c21104125ab6b3e6bc" +dependencies = [ + "ark-ec", + "ark-ff 0.5.0", + "ark-r1cs-std", + "ark-std 0.5.0", +] + +[[package]] +name = "ark-ec" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d68f2d516162846c1238e755a7c4d131b892b70cc70c471a8e3ca3ed818fce" +dependencies = [ + "ahash", + "ark-ff 0.5.0", + "ark-poly", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "educe", + "fnv", + "hashbrown 0.15.5", + "itertools 0.13.0", + "num-bigint", + "num-integer", + "num-traits", + "zeroize", +] + [[package]] name = "ark-ff" version = "0.3.0" @@ -833,7 +1037,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" dependencies = [ "quote", - "syn 2.0.114", + "syn 2.0.115", ] [[package]] @@ -871,7 +1075,51 @@ dependencies = [ "num-traits", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.115", +] + +[[package]] +name = "ark-poly" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "579305839da207f02b89cd1679e50e67b4331e2f9294a57693e5051b7703fe27" +dependencies = [ + "ahash", + "ark-ff 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "educe", + "fnv", + "hashbrown 0.15.5", +] + +[[package]] +name = "ark-r1cs-std" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "941551ef1df4c7a401de7068758db6503598e6f01850bdb2cfdb614a1f9dbea1" +dependencies = [ + "ark-ec", + "ark-ff 0.5.0", + "ark-relations", + "ark-std 0.5.0", + "educe", + "num-bigint", + "num-integer", + "num-traits", + "tracing", +] + +[[package]] +name = "ark-relations" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec46ddc93e7af44bcab5230937635b06fb5744464dd6a7e7b083e80ebd274384" +dependencies = [ + "ark-ff 0.5.0", + "ark-std 0.5.0", + "tracing", + "tracing-subscriber 0.2.25", ] [[package]] @@ -901,12 +1149,24 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f4d068aaf107ebcd7dfb52bc748f8030e0fc930ac8e360146ca54c1203088f7" dependencies = [ + "ark-serialize-derive", "ark-std 0.5.0", "arrayvec", "digest 0.10.7", "num-bigint", ] +[[package]] +name = "ark-serialize-derive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213888f660fddcca0d257e88e54ac05bca01885f258ccdf695bafd77031bb69d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", +] + [[package]] name = "ark-std" version = "0.3.0" @@ -937,6 +1197,12 @@ dependencies = [ "rand 0.8.5", ] +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + [[package]] name = "arrayvec" version = "0.7.6" @@ -946,6 +1212,27 @@ dependencies = [ "serde", ] +[[package]] +name = "assert-json-diff" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47e4f2b81832e72834d7518d8487a0396a28cc408186a2e8854c0f98011faf12" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "async-lock" +version = "3.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311" +dependencies = [ + "event-listener", + "event-listener-strategy", + "pin-project-lite", +] + [[package]] name = "async-stream" version = "0.3.6" @@ -965,7 +1252,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.115", ] [[package]] @@ -976,7 +1263,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.115", ] [[package]] @@ -996,6 +1283,64 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" +[[package]] +name = "audit" +version = "0.0.0" +dependencies = [ + "alloy-consensus", + "alloy-primitives", + "alloy-provider", + "alloy-signer-local", + "anyhow", + "async-trait", + "audit", + "aws-config", + "aws-sdk-s3", + "base-bundles", + "bytes", + "futures", + "metrics", + "metrics-derive", + "op-alloy-consensus 0.22.4", + "op-alloy-rpc-types 0.22.4", + "rdkafka", + "serde", + "serde_json", + "testcontainers", + "testcontainers-modules", + "tokio", + "tracing", + "utils", + "uuid", +] + +[[package]] +name = "audit-bin" +version = "0.0.0" +dependencies = [ + "anyhow", + "audit", + "aws-config", + "aws-credential-types", + "aws-sdk-s3", + "clap", + "dotenvy", + "rdkafka", + "tokio", + "tracing", + "utils", +] + +[[package]] +name = "aurora-engine-modexp" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "518bc5745a6264b5fd7b09dffb9667e400ee9e2bbe18555fac75e1fe9afa0df9" +dependencies = [ + "hex", + "num", +] + [[package]] name = "auto_impl" version = "1.3.0" @@ -1004,7 +1349,7 @@ checksum = "ffdcb70bdbc4d478427380519163274ac86e52916e10f0a8889adf0f96d3fee7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.115", ] [[package]] @@ -1014,2643 +1359,5648 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] -name = "base-flashtypes" -version = "0.0.0" -source = "git+https://github.com/base/base.git#720f6e1a73faabc938402b0cb617d3960db742d4" +name = "aws-config" +version = "1.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a8fc176d53d6fe85017f230405e3255cedb4a02221cb55ed6d76dccbbb099b2" dependencies = [ - "alloy-primitives", - "alloy-rpc-types-engine", - "alloy-rpc-types-eth", - "alloy-serde", - "brotli", + "aws-credential-types", + "aws-runtime", + "aws-sdk-sts", + "aws-smithy-async", + "aws-smithy-http 0.63.4", + "aws-smithy-json 0.62.4", + "aws-smithy-runtime", + "aws-smithy-runtime-api", + "aws-smithy-types", + "aws-types", "bytes", - "serde", - "serde_json", - "thiserror", + "fastrand", + "http 1.4.0", + "time", + "tokio", + "tracing", + "url", ] [[package]] -name = "base16ct" -version = "0.2.0" +name = "aws-credential-types" +version = "1.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" +checksum = "e26bbf46abc608f2dc61fd6cb3b7b0665497cc259a21520151ed98f8b37d2c79" +dependencies = [ + "aws-smithy-async", + "aws-smithy-runtime-api", + "aws-smithy-types", + "zeroize", +] [[package]] -name = "base64" -version = "0.22.1" +name = "aws-lc-rs" +version = "1.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +checksum = "7b7b6141e96a8c160799cc2d5adecd5cbbe5054cb8c7c4af53da0f83bb7ad256" +dependencies = [ + "aws-lc-sys", + "zeroize", +] [[package]] -name = "base64ct" -version = "1.8.3" +name = "aws-lc-sys" +version = "0.37.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" - -[[package]] -name = "basectl" -version = "0.0.0" +checksum = "b092fe214090261288111db7a2b2c2118e5a7f30dc2569f1732c4069a6840549" dependencies = [ - "anyhow", - "basectl-cli", - "clap", - "tokio", + "cc", + "cmake", + "dunce", + "fs_extra", ] [[package]] -name = "basectl-cli" -version = "0.0.0" +name = "aws-runtime" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0f92058d22a46adf53ec57a6a96f34447daf02bff52e8fb956c66bcd5c6ac12" dependencies = [ - "alloy-contract", - "alloy-eips", - "alloy-primitives", - "alloy-provider", - "alloy-rpc-types-eth", - "alloy-sol-types", - "anyhow", - "arboard", - "base-flashtypes", - "chrono", - "crossterm", - "dirs", - "futures-util", - "op-alloy-consensus", - "op-alloy-network", - "ratatui", - "serde", - "serde_json", - "serde_yaml", - "tokio", - "tokio-tungstenite", + "aws-credential-types", + "aws-sigv4", + "aws-smithy-async", + "aws-smithy-eventstream", + "aws-smithy-http 0.63.4", + "aws-smithy-runtime", + "aws-smithy-runtime-api", + "aws-smithy-types", + "aws-types", + "bytes", + "bytes-utils", + "fastrand", + "http 0.2.12", + "http 1.4.0", + "http-body 0.4.6", + "http-body 1.0.1", + "percent-encoding", + "pin-project-lite", "tracing", - "url", + "uuid", ] [[package]] -name = "bimap" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "230c5f1ca6a325a32553f8640d31ac9b49f2411e901e427570154868b46da4f7" - -[[package]] -name = "bit-set" -version = "0.8.0" +name = "aws-sdk-s3" +version = "1.119.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" +checksum = "1d65fddc3844f902dfe1864acb8494db5f9342015ee3ab7890270d36fbd2e01c" dependencies = [ - "bit-vec", + "aws-credential-types", + "aws-runtime", + "aws-sigv4", + "aws-smithy-async", + "aws-smithy-checksums", + "aws-smithy-eventstream", + "aws-smithy-http 0.62.6", + "aws-smithy-json 0.61.9", + "aws-smithy-runtime", + "aws-smithy-runtime-api", + "aws-smithy-types", + "aws-smithy-xml", + "aws-types", + "bytes", + "fastrand", + "hex", + "hmac", + "http 0.2.12", + "http 1.4.0", + "http-body 0.4.6", + "lru 0.12.5", + "percent-encoding", + "regex-lite", + "sha2", + "tracing", + "url", ] [[package]] -name = "bit-vec" -version = "0.8.0" +name = "aws-sdk-sts" +version = "1.98.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" +checksum = "89c4f19655ab0856375e169865c91264de965bd74c407c7f1e403184b1049409" +dependencies = [ + "aws-credential-types", + "aws-runtime", + "aws-smithy-async", + "aws-smithy-http 0.63.4", + "aws-smithy-json 0.62.4", + "aws-smithy-observability", + "aws-smithy-query", + "aws-smithy-runtime", + "aws-smithy-runtime-api", + "aws-smithy-types", + "aws-smithy-xml", + "aws-types", + "fastrand", + "http 0.2.12", + "http 1.4.0", + "regex-lite", + "tracing", +] [[package]] -name = "bitcoin-io" -version = "0.1.4" +name = "aws-sigv4" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dee39a0ee5b4095224a0cfc6bf4cc1baf0f9624b96b367e53b66d974e51d953" +checksum = "68f6ae9b71597dc5fd115d52849d7a5556ad9265885ad3492ea8d73b93bbc46e" +dependencies = [ + "aws-credential-types", + "aws-smithy-eventstream", + "aws-smithy-http 0.63.4", + "aws-smithy-runtime-api", + "aws-smithy-types", + "bytes", + "form_urlencoded", + "hex", + "hmac", + "http 0.2.12", + "http 1.4.0", + "percent-encoding", + "sha2", + "time", + "tracing", +] [[package]] -name = "bitcoin_hashes" -version = "0.14.1" +name = "aws-smithy-async" +version = "1.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26ec84b80c482df901772e931a9a681e26a1b9ee2302edeff23cb30328745c8b" +checksum = "3cba48474f1d6807384d06fec085b909f5807e16653c5af5c45dfe89539f0b70" dependencies = [ - "bitcoin-io", - "hex-conservative", + "futures-util", + "pin-project-lite", + "tokio", ] [[package]] -name = "bitflags" -version = "2.10.0" +name = "aws-smithy-checksums" +version = "0.63.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" +checksum = "87294a084b43d649d967efe58aa1f9e0adc260e13a6938eb904c0ae9b45824ae" +dependencies = [ + "aws-smithy-http 0.62.6", + "aws-smithy-types", + "bytes", + "crc-fast", + "hex", + "http 0.2.12", + "http-body 0.4.6", + "md-5", + "pin-project-lite", + "sha1", + "sha2", + "tracing", +] [[package]] -name = "bitvec" -version = "1.0.1" +name = "aws-smithy-eventstream" +version = "0.60.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +checksum = "1c0b3e587fbaa5d7f7e870544508af8ce82ea47cd30376e69e1e37c4ac746f79" dependencies = [ - "funty", - "radium", - "tap", - "wyz", + "aws-smithy-types", + "bytes", + "crc32fast", ] [[package]] -name = "block-buffer" -version = "0.10.4" +name = "aws-smithy-http" +version = "0.62.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +checksum = "826141069295752372f8203c17f28e30c464d22899a43a0c9fd9c458d469c88b" dependencies = [ - "generic-array", + "aws-smithy-eventstream", + "aws-smithy-runtime-api", + "aws-smithy-types", + "bytes", + "bytes-utils", + "futures-core", + "futures-util", + "http 0.2.12", + "http 1.4.0", + "http-body 0.4.6", + "percent-encoding", + "pin-project-lite", + "pin-utils", + "tracing", ] [[package]] -name = "blst" -version = "0.3.16" +name = "aws-smithy-http" +version = "0.63.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcdb4c7013139a150f9fc55d123186dbfaba0d912817466282c73ac49e71fb45" +checksum = "af4a8a5fe3e4ac7ee871237c340bbce13e982d37543b65700f4419e039f5d78e" dependencies = [ - "cc", - "glob", - "threadpool", - "zeroize", + "aws-smithy-runtime-api", + "aws-smithy-types", + "bytes", + "bytes-utils", + "futures-core", + "futures-util", + "http 1.4.0", + "http-body 1.0.1", + "http-body-util", + "percent-encoding", + "pin-project-lite", + "pin-utils", + "tracing", ] [[package]] -name = "borsh" -version = "1.6.0" +name = "aws-smithy-http-client" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1da5ab77c1437701eeff7c88d968729e7766172279eab0676857b3d63af7a6f" -dependencies = [ - "borsh-derive", - "cfg_aliases", +checksum = "0709f0083aa19b704132684bc26d3c868e06bd428ccc4373b0b55c3e8748a58b" +dependencies = [ + "aws-smithy-async", + "aws-smithy-runtime-api", + "aws-smithy-types", + "h2 0.3.27", + "h2 0.4.13", + "http 0.2.12", + "http 1.4.0", + "http-body 0.4.6", + "hyper 0.14.32", + "hyper 1.8.1", + "hyper-rustls 0.24.2", + "hyper-rustls 0.27.7", + "hyper-util", + "pin-project-lite", + "rustls 0.21.12", + "rustls 0.23.36", + "rustls-native-certs", + "rustls-pki-types", + "tokio", + "tokio-rustls 0.26.4", + "tower", + "tracing", ] [[package]] -name = "borsh-derive" -version = "1.6.0" +name = "aws-smithy-json" +version = "0.61.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0686c856aa6aac0c4498f936d7d6a02df690f614c03e4d906d1018062b5c5e2c" +checksum = "49fa1213db31ac95288d981476f78d05d9cbb0353d22cdf3472cc05bb02f6551" dependencies = [ - "once_cell", - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 2.0.114", + "aws-smithy-types", ] [[package]] -name = "brotli" -version = "8.0.2" +name = "aws-smithy-json" +version = "0.62.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bd8b9603c7aa97359dbd97ecf258968c95f3adddd6db2f7e7a5bef101c84560" +checksum = "27b3a779093e18cad88bbae08dc4261e1d95018c4c5b9356a52bcae7c0b6e9bb" dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", - "brotli-decompressor", + "aws-smithy-types", ] [[package]] -name = "brotli-decompressor" -version = "5.0.0" +name = "aws-smithy-observability" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03" +checksum = "4d3f39d5bb871aaf461d59144557f16d5927a5248a983a40654d9cf3b9ba183b" dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", + "aws-smithy-runtime-api", ] [[package]] -name = "bumpalo" -version = "3.19.1" +name = "aws-smithy-query" +version = "0.60.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" +checksum = "05f76a580e3d8f8961e5d48763214025a2af65c2fa4cd1fb7f270a0e107a71b0" +dependencies = [ + "aws-smithy-types", + "urlencoding", +] [[package]] -name = "byte-slice-cast" -version = "1.2.3" +name = "aws-smithy-runtime" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7575182f7272186991736b70173b0ea045398f984bf5ebbb3804736ce1330c9d" +checksum = "8fd3dfc18c1ce097cf81fced7192731e63809829c6cbf933c1ec47452d08e1aa" +dependencies = [ + "aws-smithy-async", + "aws-smithy-http 0.63.4", + "aws-smithy-http-client", + "aws-smithy-observability", + "aws-smithy-runtime-api", + "aws-smithy-types", + "bytes", + "fastrand", + "http 0.2.12", + "http 1.4.0", + "http-body 0.4.6", + "http-body 1.0.1", + "http-body-util", + "pin-project-lite", + "pin-utils", + "tokio", + "tracing", +] [[package]] -name = "bytemuck" -version = "1.25.0" +name = "aws-smithy-runtime-api" +version = "1.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" +checksum = "8c55e0837e9b8526f49e0b9bfa9ee18ddee70e853f5bc09c5d11ebceddcb0fec" +dependencies = [ + "aws-smithy-async", + "aws-smithy-types", + "bytes", + "http 0.2.12", + "http 1.4.0", + "pin-project-lite", + "tokio", + "tracing", + "zeroize", +] [[package]] -name = "byteorder" -version = "1.5.0" +name = "aws-smithy-types" +version = "1.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +checksum = "576b0d6991c9c32bc14fc340582ef148311f924d41815f641a308b5d11e8e7cd" +dependencies = [ + "base64-simd", + "bytes", + "bytes-utils", + "futures-core", + "http 0.2.12", + "http 1.4.0", + "http-body 0.4.6", + "http-body 1.0.1", + "http-body-util", + "itoa", + "num-integer", + "pin-project-lite", + "pin-utils", + "ryu", + "serde", + "time", + "tokio", + "tokio-util", +] [[package]] -name = "byteorder-lite" -version = "0.1.0" +name = "aws-smithy-xml" +version = "0.60.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" +checksum = "b53543b4b86ed43f051644f704a98c7291b3618b67adf057ee77a366fa52fcaa" +dependencies = [ + "xmlparser", +] [[package]] -name = "bytes" -version = "1.11.1" +name = "aws-types" +version = "1.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" +checksum = "6c50f3cdf47caa8d01f2be4a6663ea02418e892f9bbfd82c7b9a3a37eaccdd3a" dependencies = [ - "serde", + "aws-credential-types", + "aws-smithy-async", + "aws-smithy-runtime-api", + "aws-smithy-types", + "rustc_version 0.4.1", + "tracing", ] [[package]] -name = "c-kzg" -version = "2.1.5" +name = "axum" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e00bf4b112b07b505472dbefd19e37e53307e2bfed5a79e0cc161d58ccd0e687" +checksum = "8b52af3cb4058c895d37317bb27508dccc8e5f2d39454016b297bf4a400597b8" dependencies = [ - "blst", - "cc", - "glob", - "hex", - "libc", - "once_cell", - "serde", + "axum-core", + "bytes", + "futures-util", + "http 1.4.0", + "http-body 1.0.1", + "http-body-util", + "hyper 1.8.1", + "hyper-util", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "serde_core", + "serde_json", + "serde_path_to_error", + "sync_wrapper", + "tokio", + "tower", + "tower-layer", + "tower-service", ] [[package]] -name = "cadence" -version = "1.6.0" +name = "axum-core" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3075f133bee430b7644c54fb629b9b4420346ffa275a45c81a6babe8b09b4f51" +checksum = "08c78f31d7b1291f7ee735c1c6780ccde7785daae9a9206026862dab7d8792d1" dependencies = [ - "crossbeam-channel", + "bytes", + "futures-core", + "http 1.4.0", + "http-body 1.0.1", + "http-body-util", + "mime", + "pin-project-lite", + "sync_wrapper", + "tower-layer", + "tower-service", ] [[package]] -name = "cassowary" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" - -[[package]] -name = "castaway" -version = "0.2.4" +name = "backon" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dec551ab6e7578819132c713a93c022a05d60159dc86e7a7050223577484c55a" +checksum = "cffb0e931875b666fc4fcb20fee52e9bbd1ef836fd9e9e04ec21555f9f85f7ef" dependencies = [ - "rustversion", + "fastrand", + "tokio", ] [[package]] -name = "cc" -version = "1.2.55" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47b26a0954ae34af09b50f0de26458fa95369a0d478d8236d3f93082b219bd29" +name = "base-bundles" +version = "0.0.0" +source = "git+https://github.com/base/base?branch=main#d8adce06b1b8d86f2ccdee5688004569f42789a2" dependencies = [ - "find-msvc-tools", - "shlex", + "alloy-consensus", + "alloy-primitives", + "alloy-provider", + "alloy-serde", + "op-alloy-consensus 0.23.1", + "op-alloy-flz", + "serde", + "uuid", ] [[package]] -name = "cfg-if" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" - -[[package]] -name = "cfg_aliases" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" - -[[package]] -name = "chrono" -version = "0.4.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fac4744fb15ae8337dc853fee7fb3f4e48c0fbaa23d0afe49c447b4fab126118" +name = "base-primitives" +version = "0.0.0" +source = "git+https://github.com/base/base.git#d8adce06b1b8d86f2ccdee5688004569f42789a2" dependencies = [ - "iana-time-zone", - "js-sys", - "num-traits", + "alloy-primitives", + "alloy-rpc-types-engine", + "alloy-rpc-types-eth", + "alloy-serde", + "brotli", + "bytes", "serde", - "wasm-bindgen", - "windows-link", + "serde_json", + "thiserror 2.0.18", ] [[package]] -name = "clap" -version = "4.5.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6899ea499e3fb9305a65d5ebf6e3d2248c5fab291f300ad0a704fbe142eae31a" +name = "base-reth-rpc-types" +version = "0.0.0" +source = "git+https://github.com/base/base?branch=main#d8adce06b1b8d86f2ccdee5688004569f42789a2" dependencies = [ - "clap_builder", - "clap_derive", + "reth-optimism-evm", + "reth-rpc-eth-types", ] [[package]] -name = "clap_builder" -version = "4.5.57" +name = "base16ct" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b12c8b680195a62a8364d16b8447b01b6c2c8f9aaf68bee653be34d4245e238" -dependencies = [ - "anstream", - "anstyle", - "clap_lex", - "strsim", -] +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" [[package]] -name = "clap_derive" -version = "4.5.55" +name = "base64" +version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a92793da1a46a5f2a02a6f4c46c6496b28c43638adea8306fcb0caa1634f24e5" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn 2.0.114", -] +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] -name = "clap_lex" -version = "0.7.7" +name = "base64" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3e64b0cc0439b12df2fa678eae89a1c56a529fd067a9115f7827f1fffd22b32" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] -name = "clipboard-win" -version = "5.4.1" +name = "base64-simd" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bde03770d3df201d4fb868f2c9c59e66a3e4e2bd06692a0fe701e7103c7e84d4" +checksum = "339abbe78e73178762e23bea9dfd08e697eb3f3301cd4be981c0f78ba5859195" dependencies = [ - "error-code", + "outref", + "vsimd", ] [[package]] -name = "colorchoice" -version = "1.0.4" +name = "base64ct" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" [[package]] -name = "compact_str" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b79c4069c6cad78e2e0cdfcbd26275770669fb39fd308a752dc110e83b9af32" +name = "basectl" +version = "0.0.0" dependencies = [ - "castaway", - "cfg-if", - "itoa", - "rustversion", - "ryu", - "static_assertions", + "anyhow", + "basectl-cli", + "clap", + "tokio", ] [[package]] -name = "const-hex" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bb320cac8a0750d7f25280aa97b09c26edfe161164238ecbbb31092b079e735" +name = "basectl-cli" +version = "0.0.0" dependencies = [ - "cfg-if", - "cpufeatures", - "proptest", - "serde_core", + "alloy-contract", + "alloy-eips", + "alloy-primitives", + "alloy-provider", + "alloy-rpc-types-eth", + "alloy-sol-types", + "anyhow", + "arboard", + "base-primitives", + "chrono", + "crossterm", + "dirs", + "futures-util", + "op-alloy-consensus 0.22.4", + "op-alloy-network 0.22.4", + "ratatui", + "serde", + "serde_json", + "serde_yaml", + "tokio", + "tokio-tungstenite", + "tracing", + "url", ] [[package]] -name = "const-oid" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" - -[[package]] -name = "const_format" -version = "0.2.35" +name = "bimap" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7faa7469a93a566e9ccc1c73fe783b4a65c274c5ace346038dca9c39fe0030ad" -dependencies = [ - "const_format_proc_macros", -] +checksum = "230c5f1ca6a325a32553f8640d31ac9b49f2411e901e427570154868b46da4f7" [[package]] -name = "const_format_proc_macros" -version = "0.2.34" +name = "bindgen" +version = "0.72.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d57c2eccfb16dbac1f4e61e206105db5820c9d26c3c472bc17c774259ef7744" +checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" dependencies = [ + "bitflags 2.10.0", + "cexpr", + "clang-sys", + "itertools 0.13.0", "proc-macro2", "quote", - "unicode-xid", + "regex", + "rustc-hash", + "shlex", + "syn 2.0.115", ] [[package]] -name = "convert_case" -version = "0.10.0" +name = "bit-set" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" dependencies = [ - "unicode-segmentation", + "bit-vec", ] [[package]] -name = "core-foundation" -version = "0.9.4" +name = "bit-vec" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" -dependencies = [ - "core-foundation-sys", - "libc", -] +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" [[package]] -name = "core-foundation-sys" -version = "0.8.7" +name = "bitcoin-io" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +checksum = "2dee39a0ee5b4095224a0cfc6bf4cc1baf0f9624b96b367e53b66d974e51d953" [[package]] -name = "cpufeatures" -version = "0.2.17" +name = "bitcoin_hashes" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +checksum = "26ec84b80c482df901772e931a9a681e26a1b9ee2302edeff23cb30328745c8b" dependencies = [ - "libc", + "bitcoin-io", + "hex-conservative", ] [[package]] -name = "crc" -version = "3.4.0" +name = "bitflags" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d" -dependencies = [ - "crc-catalog", -] +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] -name = "crc-catalog" -version = "2.4.0" +name = "bitflags" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" +dependencies = [ + "serde_core", +] [[package]] -name = "crc32fast" -version = "1.5.0" +name = "bitvec" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" dependencies = [ - "cfg-if", + "funty", + "radium", + "serde", + "tap", + "wyz", ] [[package]] -name = "crossbeam-channel" -version = "0.5.15" +name = "block-buffer" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ - "crossbeam-utils", + "generic-array", ] [[package]] -name = "crossbeam-utils" -version = "0.8.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" - -[[package]] -name = "crossterm" -version = "0.28.1" +name = "blst" +version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6" +checksum = "dcdb4c7013139a150f9fc55d123186dbfaba0d912817466282c73ac49e71fb45" dependencies = [ - "bitflags", - "crossterm_winapi", - "mio", - "parking_lot", - "rustix 0.38.44", - "signal-hook", - "signal-hook-mio", - "winapi", + "cc", + "glob", + "threadpool", + "zeroize", ] [[package]] -name = "crossterm_winapi" -version = "0.9.1" +name = "bollard" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" +checksum = "97ccca1260af6a459d75994ad5acc1651bcabcbdbc41467cc9786519ab854c30" dependencies = [ + "base64 0.22.1", + "bollard-stubs", + "bytes", + "futures-core", + "futures-util", + "hex", + "home", + "http 1.4.0", + "http-body-util", + "hyper 1.8.1", + "hyper-named-pipe", + "hyper-rustls 0.27.7", + "hyper-util", + "hyperlocal", + "log", + "pin-project-lite", + "rustls 0.23.36", + "rustls-native-certs", + "rustls-pemfile", + "rustls-pki-types", + "serde", + "serde_derive", + "serde_json", + "serde_repr", + "serde_urlencoded", + "thiserror 2.0.18", + "tokio", + "tokio-util", + "tower-service", + "url", "winapi", ] [[package]] -name = "crunchy" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" - -[[package]] -name = "crypto-bigint" -version = "0.5.5" +name = "bollard-stubs" +version = "1.47.1-rc.27.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +checksum = "3f179cfbddb6e77a5472703d4b30436bff32929c0aa8a9008ecf23d1d3cdd0da" dependencies = [ - "generic-array", - "rand_core 0.6.4", - "subtle", - "zeroize", + "serde", + "serde_repr", + "serde_with", ] [[package]] -name = "crypto-common" -version = "0.1.6" +name = "borsh" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +checksum = "d1da5ab77c1437701eeff7c88d968729e7766172279eab0676857b3d63af7a6f" dependencies = [ - "generic-array", - "typenum", + "borsh-derive", + "cfg_aliases", ] [[package]] -name = "darling" -version = "0.21.3" +name = "borsh-derive" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" +checksum = "0686c856aa6aac0c4498f936d7d6a02df690f614c03e4d906d1018062b5c5e2c" dependencies = [ - "darling_core 0.21.3", - "darling_macro 0.21.3", + "once_cell", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.115", ] [[package]] -name = "darling" -version = "0.23.0" +name = "brotli" +version = "8.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" +checksum = "4bd8b9603c7aa97359dbd97ecf258968c95f3adddd6db2f7e7a5bef101c84560" dependencies = [ - "darling_core 0.23.0", - "darling_macro 0.23.0", + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", ] [[package]] -name = "darling_core" -version = "0.21.3" +name = "brotli-decompressor" +version = "5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4" +checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03" dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "serde", - "strsim", - "syn 2.0.114", + "alloc-no-stdlib", + "alloc-stdlib", ] [[package]] -name = "darling_core" -version = "0.23.0" +name = "bumpalo" +version = "3.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0" -dependencies = [ - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn 2.0.114", -] +checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" [[package]] -name = "darling_macro" -version = "0.21.3" +name = "byte-slice-cast" +version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" -dependencies = [ - "darling_core 0.21.3", - "quote", - "syn 2.0.114", -] +checksum = "7575182f7272186991736b70173b0ea045398f984bf5ebbb3804736ce1330c9d" [[package]] -name = "darling_macro" -version = "0.23.0" +name = "bytemuck" +version = "1.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" -dependencies = [ - "darling_core 0.23.0", - "quote", - "syn 2.0.114", -] +checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" [[package]] -name = "dashmap" -version = "6.1.0" +name = "byteorder" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" -dependencies = [ - "cfg-if", - "crossbeam-utils", - "hashbrown 0.14.5", - "lock_api", - "once_cell", - "parking_lot_core", -] +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] -name = "data-encoding" -version = "2.10.0" +name = "byteorder-lite" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea" +checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" [[package]] -name = "der" -version = "0.7.10" +name = "bytes" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" dependencies = [ - "const-oid", - "zeroize", + "serde", ] [[package]] -name = "deranged" -version = "0.5.5" +name = "bytes-utils" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" +checksum = "7dafe3a8757b027e2be6e4e5601ed563c55989fcf1546e933c66c8eb3a058d35" dependencies = [ - "powerfmt", - "serde_core", + "bytes", + "either", ] [[package]] -name = "derivative" -version = "2.2.0" +name = "c-kzg" +version = "2.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +checksum = "e00bf4b112b07b505472dbefd19e37e53307e2bfed5a79e0cc161d58ccd0e687" dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", + "blst", + "cc", + "glob", + "hex", + "libc", + "once_cell", + "serde", ] [[package]] -name = "derive_more" -version = "2.1.1" +name = "cadence" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" +checksum = "d7aff0c323415907f37007d645d7499c378df47efb3e33ffc1f397fa4e549b2e" dependencies = [ - "derive_more-impl", + "crossbeam-channel", ] [[package]] -name = "derive_more-impl" -version = "2.1.1" +name = "cassowary" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" -dependencies = [ - "convert_case", - "proc-macro2", - "quote", - "rustc_version 0.4.1", - "syn 2.0.114", - "unicode-xid", -] +checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" [[package]] -name = "digest" -version = "0.9.0" +name = "castaway" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +checksum = "dec551ab6e7578819132c713a93c022a05d60159dc86e7a7050223577484c55a" dependencies = [ - "generic-array", + "rustversion", ] [[package]] -name = "digest" -version = "0.10.7" +name = "cc" +version = "1.2.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +checksum = "47b26a0954ae34af09b50f0de26458fa95369a0d478d8236d3f93082b219bd29" dependencies = [ - "block-buffer", - "const-oid", - "crypto-common", - "subtle", + "find-msvc-tools", + "jobserver", + "libc", + "shlex", ] [[package]] -name = "dirs" -version = "6.0.0" +name = "cesu8" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" -dependencies = [ - "dirs-sys", -] +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" [[package]] -name = "dirs-sys" -version = "0.5.0" +name = "cexpr" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" dependencies = [ - "libc", - "option-ext", - "redox_users", - "windows-sys 0.61.2", + "nom", ] [[package]] -name = "dispatch2" -version = "0.3.0" +name = "cfg-if" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" -dependencies = [ - "bitflags", - "objc2", -] +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] -name = "displaydoc" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.114", -] - -[[package]] -name = "dotenvy" -version = "0.15.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" - -[[package]] -name = "dunce" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" - -[[package]] -name = "dyn-clone" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" - -[[package]] -name = "ecdsa" -version = "0.16.9" +name = "cfg_aliases" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" -dependencies = [ - "der", - "digest 0.10.7", - "elliptic-curve", - "rfc6979", - "serdect", - "signature", - "spki", -] +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] -name = "educe" -version = "0.6.0" +name = "chrono" +version = "0.4.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7bc049e1bd8cdeb31b68bbd586a9464ecf9f3944af3958a7a9d0f8b9799417" +checksum = "fac4744fb15ae8337dc853fee7fb3f4e48c0fbaa23d0afe49c447b4fab126118" dependencies = [ - "enum-ordinalize", - "proc-macro2", - "quote", - "syn 2.0.114", + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-link", ] [[package]] -name = "either" -version = "1.15.0" +name = "clang-sys" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" dependencies = [ - "serde", + "glob", + "libc", + "libloading", ] [[package]] -name = "elliptic-curve" -version = "0.13.8" +name = "clap" +version = "4.5.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +checksum = "63be97961acde393029492ce0be7a1af7e323e6bae9511ebfac33751be5e6806" dependencies = [ - "base16ct", - "crypto-bigint", - "digest 0.10.7", - "ff", - "generic-array", - "group", - "pkcs8", - "rand_core 0.6.4", - "sec1", - "serdect", - "subtle", - "zeroize", + "clap_builder", + "clap_derive", ] [[package]] -name = "enum-ordinalize" -version = "4.3.2" +name = "clap_builder" +version = "4.5.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a1091a7bb1f8f2c4b28f1fe2cef4980ca2d410a3d727d67ecc3178c9b0800f0" +checksum = "7f13174bda5dfd69d7e947827e5af4b0f2f94a4a3ee92912fba07a66150f21e2" dependencies = [ - "enum-ordinalize-derive", + "anstream", + "anstyle", + "clap_lex", + "strsim", ] [[package]] -name = "enum-ordinalize-derive" -version = "4.3.2" +name = "clap_derive" +version = "4.5.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ca9601fb2d62598ee17836250842873a413586e5d7ed88b356e38ddbb0ec631" +checksum = "a92793da1a46a5f2a02a6f4c46c6496b28c43638adea8306fcb0caa1634f24e5" dependencies = [ + "heck", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.115", ] [[package]] -name = "equivalent" -version = "1.0.2" +name = "clap_lex" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" +checksum = "3a822ea5bc7590f9d40f1ba12c0dc3c2760f3482c6984db1573ad11031420831" [[package]] -name = "errno" -version = "0.3.14" +name = "clipboard-win" +version = "5.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +checksum = "bde03770d3df201d4fb868f2c9c59e66a3e4e2bd06692a0fe701e7103c7e84d4" dependencies = [ - "libc", - "windows-sys 0.61.2", + "error-code", ] [[package]] -name = "error-code" -version = "3.3.2" +name = "cmake" +version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dea2df4cf52843e0452895c455a1a2cfbb842a1e7329671acf418fdc53ed4c59" +checksum = "75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d" +dependencies = [ + "cc", +] [[package]] -name = "fastrand" -version = "2.3.0" +name = "colorchoice" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" [[package]] -name = "fastrlp" -version = "0.3.1" +name = "combine" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "139834ddba373bbdd213dffe02c8d110508dcf1726c2be27e8d1f7d7e1856418" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" dependencies = [ - "arrayvec", - "auto_impl", "bytes", + "memchr", ] [[package]] -name = "fastrlp" -version = "0.4.0" +name = "compact_str" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce8dba4714ef14b8274c371879b175aa55b16b30f269663f19d576f380018dc4" +checksum = "3b79c4069c6cad78e2e0cdfcbd26275770669fb39fd308a752dc110e83b9af32" dependencies = [ - "arrayvec", - "auto_impl", - "bytes", + "castaway", + "cfg-if", + "itoa", + "rustversion", + "ryu", + "static_assertions", ] [[package]] -name = "fax" -version = "0.2.6" +name = "concurrent-queue" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f05de7d48f37cd6730705cbca900770cab77a89f413d23e100ad7fad7795a0ab" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" dependencies = [ - "fax_derive", + "crossbeam-utils", ] [[package]] -name = "fax_derive" -version = "0.2.0" +name = "const-hex" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0aca10fb742cb43f9e7bb8467c91aa9bcb8e3ffbc6a6f7389bb93ffc920577d" +checksum = "3bb320cac8a0750d7f25280aa97b09c26edfe161164238ecbbb31092b079e735" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.114", + "cfg-if", + "cpufeatures", + "proptest", + "serde_core", ] [[package]] -name = "fdeflate" -version = "0.3.7" +name = "const-oid" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" -dependencies = [ - "simd-adler32", -] +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] -name = "ff" -version = "0.13.1" +name = "const_format" +version = "0.2.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" +checksum = "7faa7469a93a566e9ccc1c73fe783b4a65c274c5ace346038dca9c39fe0030ad" dependencies = [ - "rand_core 0.6.4", - "subtle", + "const_format_proc_macros", ] [[package]] -name = "find-msvc-tools" -version = "0.1.9" +name = "const_format_proc_macros" +version = "0.2.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" +checksum = "1d57c2eccfb16dbac1f4e61e206105db5820c9d26c3c472bc17c774259ef7744" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] [[package]] -name = "fixed-hash" -version = "0.8.0" +name = "convert_case" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" +checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9" dependencies = [ - "byteorder", - "rand 0.8.5", - "rustc-hex", - "static_assertions", + "unicode-segmentation", ] [[package]] -name = "flate2" -version = "1.1.9" +name = "core-foundation" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" dependencies = [ - "crc32fast", - "miniz_oxide", + "core-foundation-sys", + "libc", ] [[package]] -name = "fnv" -version = "1.0.7" +name = "core-foundation" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] [[package]] -name = "foldhash" -version = "0.1.5" +name = "core-foundation-sys" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] -name = "foldhash" -version = "0.2.0" +name = "cpufeatures" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] [[package]] -name = "foreign-types" -version = "0.3.2" +name = "crc" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d" dependencies = [ - "foreign-types-shared", + "crc-catalog", ] [[package]] -name = "foreign-types-shared" -version = "0.1.1" +name = "crc-catalog" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" [[package]] -name = "form_urlencoded" -version = "1.2.2" +name = "crc-fast" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +checksum = "6ddc2d09feefeee8bd78101665bd8645637828fa9317f9f292496dbbd8c65ff3" dependencies = [ - "percent-encoding", + "crc", + "digest 0.10.7", + "rand 0.9.2", + "regex", + "rustversion", ] [[package]] -name = "funty" -version = "2.0.0" +name = "crc32fast" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] [[package]] -name = "futures" -version = "0.3.31" +name = "critical-section" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" [[package]] -name = "futures-channel" -version = "0.3.31" +name = "crossbeam-channel" +version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" dependencies = [ - "futures-core", - "futures-sink", + "crossbeam-utils", ] [[package]] -name = "futures-core" -version = "0.3.31" +name = "crossbeam-deque" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] [[package]] -name = "futures-executor" -version = "0.3.31" +name = "crossbeam-epoch" +version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" dependencies = [ - "futures-core", - "futures-task", - "futures-util", + "crossbeam-utils", ] [[package]] -name = "futures-io" -version = "0.3.31" +name = "crossbeam-utils" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] -name = "futures-macro" -version = "0.3.31" +name = "crossterm" +version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.114", + "bitflags 2.10.0", + "crossterm_winapi", + "mio", + "parking_lot", + "rustix 0.38.44", + "signal-hook", + "signal-hook-mio", + "winapi", ] [[package]] -name = "futures-sink" -version = "0.3.31" +name = "crossterm_winapi" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" +checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" +dependencies = [ + "winapi", +] [[package]] -name = "futures-task" -version = "0.3.31" +name = "crunchy" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" [[package]] -name = "futures-util" -version = "0.3.31" +name = "crypto-bigint" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", + "generic-array", + "rand_core 0.6.4", + "subtle", + "zeroize", ] [[package]] -name = "futures-utils-wasm" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42012b0f064e01aa58b545fe3727f90f7dd4020f4a3ea735b50344965f5a57e9" - -[[package]] -name = "generic-array" -version = "0.14.9" +name = "crypto-common" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ + "generic-array", "typenum", - "version_check", - "zeroize", ] [[package]] -name = "gethostname" -version = "1.1.0" +name = "darling" +version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bd49230192a3797a9a4d6abe9b3eed6f7fa4c8a8a4947977c6f80025f92cbd8" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" dependencies = [ - "rustix 1.1.3", - "windows-link", + "darling_core 0.20.11", + "darling_macro 0.20.11", ] [[package]] -name = "getrandom" -version = "0.2.17" +name = "darling" +version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" dependencies = [ - "cfg-if", - "js-sys", - "libc", - "wasi", - "wasm-bindgen", + "darling_core 0.21.3", + "darling_macro 0.21.3", ] [[package]] -name = "getrandom" -version = "0.3.4" +name = "darling" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" dependencies = [ - "cfg-if", - "libc", - "r-efi", - "wasip2", + "darling_core 0.23.0", + "darling_macro 0.23.0", ] [[package]] -name = "glob" -version = "0.3.3" +name = "darling_core" +version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.115", +] [[package]] -name = "group" -version = "0.13.0" +name = "darling_core" +version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4" dependencies = [ - "ff", - "rand_core 0.6.4", - "subtle", + "fnv", + "ident_case", + "proc-macro2", + "quote", + "serde", + "strsim", + "syn 2.0.115", ] [[package]] -name = "half" -version = "2.7.1" +name = "darling_core" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" +checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0" dependencies = [ - "cfg-if", - "crunchy", - "zerocopy", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.115", ] [[package]] -name = "hashbrown" -version = "0.12.3" +name = "darling_macro" +version = "0.20.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +dependencies = [ + "darling_core 0.20.11", + "quote", + "syn 2.0.115", +] [[package]] -name = "hashbrown" -version = "0.14.5" +name = "darling_macro" +version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" +dependencies = [ + "darling_core 0.21.3", + "quote", + "syn 2.0.115", +] [[package]] -name = "hashbrown" -version = "0.15.5" +name = "darling_macro" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" dependencies = [ - "allocator-api2", - "equivalent", - "foldhash 0.1.5", + "darling_core 0.23.0", + "quote", + "syn 2.0.115", ] [[package]] -name = "hashbrown" -version = "0.16.1" +name = "dashmap" +version = "6.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" +checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" dependencies = [ - "allocator-api2", - "equivalent", - "foldhash 0.2.0", - "serde", - "serde_core", + "cfg-if", + "crossbeam-utils", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", ] [[package]] -name = "heck" -version = "0.5.0" +name = "data-encoding" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea" [[package]] -name = "hermit-abi" -version = "0.5.2" +name = "deadpool" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" +checksum = "0be2b1d1d6ec8d846f05e137292d0b89133caf95ef33695424c09568bdd39b1b" +dependencies = [ + "deadpool-runtime", + "lazy_static", + "num_cpus", + "tokio", +] [[package]] -name = "hex" -version = "0.4.3" +name = "deadpool-runtime" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +checksum = "092966b41edc516079bdf31ec78a2e0588d1d0c08f78b91d8307215928642b2b" [[package]] -name = "hex-conservative" -version = "0.2.2" +name = "der" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fda06d18ac606267c40c04e41b9947729bf8b9efe74bd4e82b61a5f26a510b9f" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" dependencies = [ - "arrayvec", + "const-oid", + "zeroize", ] [[package]] -name = "hmac" -version = "0.12.1" +name = "deranged" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +checksum = "cc3dc5ad92c2e2d1c193bbbbdf2ea477cb81331de4f3103f267ca18368b988c4" dependencies = [ - "digest 0.10.7", + "powerfmt", + "serde_core", ] [[package]] -name = "http" -version = "1.4.0" +name = "derivative" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" dependencies = [ - "bytes", - "itoa", + "proc-macro2", + "quote", + "syn 1.0.109", ] [[package]] -name = "http-body" -version = "1.0.1" +name = "derive-where" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +checksum = "ef941ded77d15ca19b40374869ac6000af1c9f2a4c0f3d4c70926287e6364a8f" dependencies = [ - "bytes", - "http", + "proc-macro2", + "quote", + "syn 2.0.115", ] [[package]] -name = "http-body-util" -version = "0.1.3" +name = "derive_more" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" dependencies = [ - "bytes", - "futures-core", - "http", - "http-body", - "pin-project-lite", + "derive_more-impl", ] [[package]] -name = "httparse" -version = "1.10.1" +name = "derive_more-impl" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version 0.4.1", + "syn 2.0.115", + "unicode-xid", +] [[package]] -name = "hyper" -version = "1.8.1" +name = "digest" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" dependencies = [ - "atomic-waker", - "bytes", - "futures-channel", - "futures-core", - "http", - "http-body", - "httparse", - "itoa", - "pin-project-lite", - "pin-utils", - "smallvec", - "tokio", - "want", + "generic-array", ] [[package]] -name = "hyper-tls" -version = "0.6.0" +name = "digest" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "bytes", - "http-body-util", - "hyper", - "hyper-util", - "native-tls", - "tokio", - "tokio-native-tls", - "tower-service", + "block-buffer", + "const-oid", + "crypto-common", + "subtle", ] [[package]] -name = "hyper-util" -version = "0.1.20" +name = "dirs" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" +checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" dependencies = [ - "base64", - "bytes", - "futures-channel", - "futures-util", - "http", - "http-body", - "hyper", - "ipnet", - "libc", - "percent-encoding", - "pin-project-lite", - "socket2", - "tokio", - "tower-service", - "tracing", + "dirs-sys", ] [[package]] -name = "iana-time-zone" -version = "0.1.65" +name = "dirs-sys" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "log", - "wasm-bindgen", - "windows-core", + "libc", + "option-ext", + "redox_users", + "windows-sys 0.61.2", ] [[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" +name = "dispatch2" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" dependencies = [ - "cc", + "bitflags 2.10.0", + "objc2", ] [[package]] -name = "icu_collections" -version = "2.1.1" +name = "displaydoc" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ - "displaydoc", - "potential_utf", - "yoke", - "zerofrom", - "zerovec", + "proc-macro2", + "quote", + "syn 2.0.115", ] [[package]] -name = "icu_locale_core" -version = "2.1.1" +name = "docker_credential" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" +checksum = "1d89dfcba45b4afad7450a99b39e751590463e45c04728cf555d36bb66940de8" dependencies = [ - "displaydoc", - "litemap", - "tinystr", - "writeable", - "zerovec", + "base64 0.21.7", + "serde", + "serde_json", ] [[package]] -name = "icu_normalizer" -version = "2.1.1" +name = "dotenvy" +version = "0.15.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" -dependencies = [ - "icu_collections", - "icu_normalizer_data", - "icu_properties", - "icu_provider", - "smallvec", - "zerovec", -] +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" [[package]] -name = "icu_normalizer_data" -version = "2.1.1" +name = "downcast" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" +checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1" [[package]] -name = "icu_properties" -version = "2.1.2" +name = "dunce" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" -dependencies = [ - "icu_collections", - "icu_locale_core", - "icu_properties_data", - "icu_provider", - "zerotrie", - "zerovec", -] +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" [[package]] -name = "icu_properties_data" -version = "2.1.2" +name = "dyn-clone" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" [[package]] -name = "icu_provider" -version = "2.1.1" +name = "ecdsa" +version = "0.16.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" dependencies = [ - "displaydoc", - "icu_locale_core", - "writeable", - "yoke", - "zerofrom", - "zerotrie", - "zerovec", + "der", + "digest 0.10.7", + "elliptic-curve", + "rfc6979", + "serdect", + "signature", + "spki", ] [[package]] -name = "ident_case" -version = "1.0.1" +name = "educe" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" +checksum = "1d7bc049e1bd8cdeb31b68bbd586a9464ecf9f3944af3958a7a9d0f8b9799417" +dependencies = [ + "enum-ordinalize", + "proc-macro2", + "quote", + "syn 2.0.115", +] [[package]] -name = "idna" -version = "1.1.0" +name = "either" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" dependencies = [ - "idna_adapter", - "smallvec", - "utf8_iter", + "serde", ] [[package]] -name = "idna_adapter" -version = "1.2.1" +name = "elliptic-curve" +version = "0.13.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" dependencies = [ - "icu_normalizer", - "icu_properties", + "base16ct", + "crypto-bigint", + "digest 0.10.7", + "ff", + "generic-array", + "group", + "pkcs8", + "rand_core 0.6.4", + "sec1", + "serdect", + "subtle", + "zeroize", ] [[package]] -name = "image" -version = "0.25.9" +name = "enr" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6506c6c10786659413faa717ceebcb8f70731c0a60cbae39795fdf114519c1a" +checksum = "851bd664a3d3a3c175cff92b2f0df02df3c541b4895d0ae307611827aae46152" dependencies = [ - "bytemuck", - "byteorder-lite", - "moxcms", - "num-traits", - "png", - "tiff", + "alloy-rlp", + "base64 0.22.1", + "bytes", + "hex", + "log", + "rand 0.8.5", + "secp256k1 0.30.0", + "sha3", + "zeroize", ] [[package]] -name = "impl-codec" -version = "0.6.0" +name = "enum-ordinalize" +version = "4.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" +checksum = "4a1091a7bb1f8f2c4b28f1fe2cef4980ca2d410a3d727d67ecc3178c9b0800f0" dependencies = [ - "parity-scale-codec", + "enum-ordinalize-derive", ] [[package]] -name = "impl-trait-for-tuples" -version = "0.2.3" +name = "enum-ordinalize-derive" +version = "4.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" +checksum = "8ca9601fb2d62598ee17836250842873a413586e5d7ed88b356e38ddbb0ec631" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.115", ] [[package]] -name = "indexmap" -version = "1.9.3" +name = "equivalent" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ - "autocfg", - "hashbrown 0.12.3", - "serde", + "libc", + "windows-sys 0.61.2", ] [[package]] -name = "indexmap" -version = "2.13.0" +name = "error-code" +version = "3.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +checksum = "dea2df4cf52843e0452895c455a1a2cfbb842a1e7329671acf418fdc53ed4c59" + +[[package]] +name = "etcetera" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" dependencies = [ - "equivalent", - "hashbrown 0.16.1", + "cfg-if", + "home", + "windows-sys 0.48.0", +] + +[[package]] +name = "ethereum_serde_utils" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dc1355dbb41fbbd34ec28d4fb2a57d9a70c67ac3c19f6a5ca4d4a176b9e997a" +dependencies = [ + "alloy-primitives", + "hex", "serde", - "serde_core", + "serde_derive", + "serde_json", ] [[package]] -name = "indoc" -version = "2.0.7" +name = "ethereum_ssz" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706" +checksum = "0dcddb2554d19cde19b099fadddde576929d7a4d0c1cd3512d1fd95cf174375c" dependencies = [ - "rustversion", + "alloy-primitives", + "ethereum_serde_utils", + "itertools 0.13.0", + "serde", + "serde_derive", + "smallvec", + "typenum", ] [[package]] -name = "instability" -version = "0.3.11" +name = "ethereum_ssz_derive" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357b7205c6cd18dd2c86ed312d1e70add149aea98e7ef72b9fdf0270e555c11d" +checksum = "a657b6b3b7e153637dc6bdc6566ad9279d9ee11a15b12cfb24a2e04360637e9f" dependencies = [ - "darling 0.23.0", - "indoc", + "darling 0.20.11", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.115", ] [[package]] -name = "ipnet" -version = "2.11.0" +name = "event-listener" +version = "5.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] [[package]] -name = "iri-string" -version = "0.7.10" +name = "event-listener-strategy" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" dependencies = [ - "memchr", - "serde", + "event-listener", + "pin-project-lite", ] [[package]] -name = "is_terminal_polyfill" -version = "1.70.2" +name = "fastrand" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] -name = "itertools" -version = "0.10.5" +name = "fastrlp" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +checksum = "139834ddba373bbdd213dffe02c8d110508dcf1726c2be27e8d1f7d7e1856418" dependencies = [ - "either", + "arrayvec", + "auto_impl", + "bytes", ] [[package]] -name = "itertools" -version = "0.13.0" +name = "fastrlp" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +checksum = "ce8dba4714ef14b8274c371879b175aa55b16b30f269663f19d576f380018dc4" dependencies = [ - "either", + "arrayvec", + "auto_impl", + "bytes", ] [[package]] -name = "itertools" -version = "0.14.0" +name = "fax" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +checksum = "f05de7d48f37cd6730705cbca900770cab77a89f413d23e100ad7fad7795a0ab" dependencies = [ - "either", + "fax_derive", ] [[package]] -name = "itoa" -version = "1.0.17" +name = "fax_derive" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" +checksum = "a0aca10fb742cb43f9e7bb8467c91aa9bcb8e3ffbc6a6f7389bb93ffc920577d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", +] [[package]] -name = "js-sys" -version = "0.3.85" +name = "fdeflate" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3" +checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" dependencies = [ - "once_cell", - "wasm-bindgen", + "simd-adler32", ] [[package]] -name = "jsonwebtoken" -version = "9.3.1" +name = "ff" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a87cc7a48537badeae96744432de36f4be2b4a34a05a5ef32e9dd8a1c169dde" +checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" dependencies = [ - "base64", - "js-sys", - "pem", - "ring", - "serde", - "serde_json", - "simple_asn1", + "rand_core 0.6.4", + "subtle", ] [[package]] -name = "k256" -version = "0.13.4" +name = "filetime" +version = "0.2.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" +checksum = "f98844151eee8917efc50bd9e8318cb963ae8b297431495d3f758616ea5c57db" dependencies = [ "cfg-if", - "ecdsa", - "elliptic-curve", - "once_cell", - "serdect", - "sha2", + "libc", + "libredox", ] [[package]] -name = "keccak" -version = "0.1.5" +name = "find-msvc-tools" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" -dependencies = [ - "cpufeatures", -] +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" [[package]] -name = "keccak-asm" -version = "0.1.5" +name = "fixed-hash" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b646a74e746cd25045aa0fd42f4f7f78aa6d119380182c7e63a5593c4ab8df6f" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" dependencies = [ - "digest 0.10.7", - "sha3-asm", + "byteorder", + "rand 0.8.5", + "rustc-hex", + "static_assertions", ] [[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" - -[[package]] -name = "libc" -version = "0.2.180" +name = "fixed-map" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" +checksum = "86ed19add84e8cb9e8cc5f7074de0324247149ffef0b851e215fb0edc50c229b" +dependencies = [ + "fixed-map-derive", + "serde", +] [[package]] -name = "libm" -version = "0.2.16" +name = "fixed-map-derive" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" +checksum = "6dc7a9cb3326bafb80642c5ce99b39a2c0702d4bfa8ee8a3e773791a6cbe2407" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", +] [[package]] -name = "libredox" -version = "0.1.12" +name = "flate2" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" dependencies = [ - "bitflags", - "libc", + "crc32fast", + "miniz_oxide", ] [[package]] -name = "linux-raw-sys" -version = "0.4.15" +name = "fnv" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] -name = "linux-raw-sys" -version = "0.11.0" +name = "foldhash" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" [[package]] -name = "litemap" -version = "0.8.1" +name = "foldhash" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" [[package]] -name = "lock_api" -version = "0.4.14" +name = "foreign-types" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" dependencies = [ - "scopeguard", + "foreign-types-shared", ] [[package]] -name = "log" -version = "0.4.29" +name = "foreign-types-shared" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] -name = "lru" -version = "0.12.5" +name = "form_urlencoded" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" dependencies = [ - "hashbrown 0.15.5", + "percent-encoding", ] [[package]] -name = "lru" -version = "0.16.3" +name = "fragile" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1dc47f592c06f33f8e3aea9591776ec7c9f9e4124778ff8a3c3b87159f7e593" -dependencies = [ - "hashbrown 0.16.1", -] +checksum = "28dd6caf6059519a65843af8fe2a3ae298b14b80179855aeb4adc2c1934ee619" [[package]] -name = "macro-string" -version = "0.1.4" +name = "fs_extra" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b27834086c65ec3f9387b096d66e99f221cf081c2b738042aa252bcd41204e3" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.114", -] +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" [[package]] -name = "matchers" -version = "0.2.0" +name = "funty" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" -dependencies = [ - "regex-automata", -] +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] -name = "memchr" -version = "2.8.0" +name = "futures" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" - -[[package]] -name = "mempool-rebroadcaster" -version = "0.0.0" -dependencies = [ - "alloy-consensus", - "alloy-eips", - "alloy-primitives", - "alloy-provider", - "alloy-rpc-types", - "alloy-rpc-types-eth", - "alloy-trie", - "serde", - "serde_json", - "tokio", - "tracing", -] - -[[package]] -name = "mempool-rebroadcaster-bin" -version = "0.1.0" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ - "clap", - "dotenvy", - "mempool-rebroadcaster", - "tokio", - "tracing", - "tracing-subscriber", + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", ] [[package]] -name = "miniz_oxide" -version = "0.8.9" +name = "futures-channel" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ - "adler2", - "simd-adler32", + "futures-core", + "futures-sink", ] [[package]] -name = "mio" -version = "1.1.1" +name = "futures-core" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" -dependencies = [ - "libc", - "log", - "wasi", - "windows-sys 0.61.2", -] +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] -name = "moxcms" -version = "0.7.11" +name = "futures-executor" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac9557c559cd6fc9867e122e20d2cbefc9ca29d80d027a8e39310920ed2f0a97" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ - "num-traits", - "pxfm", + "futures-core", + "futures-task", + "futures-util", ] [[package]] -name = "native-tls" -version = "0.2.14" +name = "futures-io" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" -dependencies = [ - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] -name = "nu-ansi-term" -version = "0.50.3" +name = "futures-macro" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ - "windows-sys 0.61.2", + "proc-macro2", + "quote", + "syn 2.0.115", ] [[package]] -name = "num-bigint" -version = "0.4.6" +name = "futures-sink" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" -dependencies = [ - "num-integer", - "num-traits", -] +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] -name = "num-conv" -version = "0.2.0" +name = "futures-task" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] -name = "num-integer" -version = "0.1.46" +name = "futures-util" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ - "num-traits", + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", ] [[package]] -name = "num-traits" -version = "0.2.19" +name = "futures-utils-wasm" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" -dependencies = [ - "autocfg", - "libm", -] +checksum = "42012b0f064e01aa58b545fe3727f90f7dd4020f4a3ea735b50344965f5a57e9" [[package]] -name = "num_cpus" -version = "1.17.0" +name = "generic-array" +version = "0.14.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" +checksum = "4bb6743198531e02858aeaea5398fcc883e71851fcbcb5a2f773e2fb6cb1edf2" dependencies = [ - "hermit-abi", - "libc", + "typenum", + "version_check", + "zeroize", ] [[package]] -name = "num_enum" -version = "0.7.5" +name = "gethostname" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1207a7e20ad57b847bbddc6776b968420d38292bbfe2089accff5e19e82454c" +checksum = "1bd49230192a3797a9a4d6abe9b3eed6f7fa4c8a8a4947977c6f80025f92cbd8" dependencies = [ - "num_enum_derive", - "rustversion", + "rustix 1.1.3", + "windows-link", ] [[package]] -name = "num_enum_derive" -version = "0.7.5" +name = "getrandom" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.114", + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", ] [[package]] -name = "nybbles" -version = "0.4.8" +name = "getrandom" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d49ff0c0d00d4a502b39df9af3a525e1efeb14b9dabb5bb83335284c1309210" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ - "alloy-rlp", "cfg-if", - "proptest", - "ruint", - "serde", - "smallvec", + "js-sys", + "libc", + "r-efi", + "wasip2", + "wasm-bindgen", ] [[package]] -name = "objc2" -version = "0.6.3" +name = "getrandom" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7c2599ce0ec54857b29ce62166b0ed9b4f6f1a70ccc9a71165b6154caca8c05" +checksum = "139ef39800118c7683f2fd3c98c1b23c09ae076556b435f8e9064ae108aaeeec" dependencies = [ - "objc2-encode", + "cfg-if", + "libc", + "r-efi", + "wasip2", + "wasip3", ] [[package]] -name = "objc2-app-kit" -version = "0.3.2" +name = "glob" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c" -dependencies = [ - "bitflags", - "objc2", - "objc2-core-graphics", - "objc2-foundation", -] +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" [[package]] -name = "objc2-core-foundation" -version = "0.3.2" +name = "group" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ - "bitflags", - "dispatch2", - "objc2", + "ff", + "rand_core 0.6.4", + "subtle", ] [[package]] -name = "objc2-core-graphics" -version = "0.3.2" +name = "h2" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807" +checksum = "0beca50380b1fc32983fc1cb4587bfa4bb9e78fc259aad4a0032d2080309222d" dependencies = [ - "bitflags", - "dispatch2", - "objc2", - "objc2-core-foundation", - "objc2-io-surface", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http 0.2.12", + "indexmap 2.13.0", + "slab", + "tokio", + "tokio-util", + "tracing", ] [[package]] -name = "objc2-encode" -version = "4.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" - -[[package]] -name = "objc2-foundation" -version = "0.3.2" +name = "h2" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" +checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54" dependencies = [ - "bitflags", - "objc2", - "objc2-core-foundation", + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http 1.4.0", + "indexmap 2.13.0", + "slab", + "tokio", + "tokio-util", + "tracing", ] [[package]] -name = "objc2-io-surface" -version = "0.3.2" +name = "half" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180788110936d59bab6bd83b6060ffdfffb3b922ba1396b312ae795e1de9d81d" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" dependencies = [ - "bitflags", - "objc2", - "objc2-core-foundation", + "cfg-if", + "crunchy", + "zerocopy", ] [[package]] -name = "once_cell" -version = "1.21.3" +name = "hashbrown" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] -name = "once_cell_polyfill" -version = "1.70.2" +name = "hashbrown" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" [[package]] -name = "op-alloy-consensus" -version = "0.22.4" +name = "hashbrown" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "726da827358a547be9f1e37c2a756b9e3729cb0350f43408164794b370cad8ae" -dependencies = [ - "alloy-consensus", - "alloy-eips", - "alloy-network", - "alloy-primitives", - "alloy-rlp", - "alloy-rpc-types-eth", - "alloy-serde", - "derive_more", - "serde", - "thiserror", -] +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] -name = "op-alloy-network" -version = "0.22.4" +name = "hashbrown" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63f27e65be273ec8fcb0b6af0fd850b550979465ab93423705ceb3dfddbd2ab" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ - "alloy-consensus", - "alloy-network", - "alloy-primitives", - "alloy-provider", - "alloy-rpc-types-eth", - "alloy-signer", - "op-alloy-consensus", - "op-alloy-rpc-types", + "allocator-api2", + "equivalent", + "foldhash 0.1.5", ] [[package]] -name = "op-alloy-rpc-types" -version = "0.22.4" +name = "hashbrown" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "562dd4462562c41f9fdc4d860858c40e14a25df7f983ae82047f15f08fce4d19" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" dependencies = [ - "alloy-consensus", - "alloy-eips", - "alloy-network-primitives", - "alloy-primitives", - "alloy-rpc-types-eth", - "alloy-serde", - "derive_more", - "op-alloy-consensus", + "allocator-api2", + "equivalent", + "foldhash 0.2.0", "serde", - "serde_json", - "thiserror", + "serde_core", ] [[package]] -name = "openssl" -version = "0.10.75" +name = "heck" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328" -dependencies = [ - "bitflags", - "cfg-if", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] -name = "openssl-macros" -version = "0.1.1" +name = "hermit-abi" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.114", -] +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" [[package]] -name = "openssl-probe" -version = "0.1.6" +name = "hex" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] -name = "openssl-sys" -version = "0.9.111" +name = "hex-conservative" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321" +checksum = "fda06d18ac606267c40c04e41b9947729bf8b9efe74bd4e82b61a5f26a510b9f" dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", + "arrayvec", ] [[package]] -name = "opentelemetry" -version = "0.31.0" +name = "hmac" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b84bcd6ae87133e903af7ef497404dda70c60d0ea14895fc8a5e6722754fc2a0" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "futures-core", - "futures-sink", - "js-sys", - "pin-project-lite", - "thiserror", - "tracing", + "digest 0.10.7", ] [[package]] -name = "opentelemetry-http" -version = "0.31.0" +name = "home" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7a6d09a73194e6b66df7c8f1b680f156d916a1a942abf2de06823dd02b7855d" +checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" dependencies = [ - "async-trait", - "bytes", - "http", - "opentelemetry", + "windows-sys 0.61.2", ] [[package]] -name = "option-ext" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" - -[[package]] -name = "parity-scale-codec" -version = "3.7.5" +name = "http" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "799781ae679d79a948e13d4824a40970bfa500058d245760dd857301059810fa" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" dependencies = [ - "arrayvec", - "bitvec", - "byte-slice-cast", - "const_format", - "impl-trait-for-tuples", - "parity-scale-codec-derive", - "rustversion", - "serde", + "bytes", + "fnv", + "itoa", ] [[package]] -name = "parity-scale-codec-derive" -version = "3.7.5" +name = "http" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34b4653168b563151153c9e4c08ebed57fb8262bebfa79711552fa983c623e7a" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 2.0.114", + "bytes", + "itoa", ] [[package]] -name = "parking_lot" -version = "0.12.5" +name = "http-body" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ - "lock_api", - "parking_lot_core", + "bytes", + "http 0.2.12", + "pin-project-lite", ] [[package]] -name = "parking_lot_core" -version = "0.9.12" +name = "http-body" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-link", + "bytes", + "http 1.4.0", ] [[package]] -name = "paste" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" - -[[package]] -name = "pem" -version = "3.0.6" +name = "http-body-util" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d30c53c26bc5b31a98cd02d20f25a7c8567146caf63ed593a9d87b2775291be" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ - "base64", - "serde_core", + "bytes", + "futures-core", + "http 1.4.0", + "http-body 1.0.1", + "pin-project-lite", ] [[package]] -name = "percent-encoding" -version = "2.3.2" +name = "httparse" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" [[package]] -name = "pest" -version = "2.8.6" +name = "httpdate" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0848c601009d37dfa3430c4666e147e49cdcf1b92ecd3e63657d8a5f19da662" -dependencies = [ - "memchr", - "ucd-trie", -] +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] -name = "pharos" -version = "0.5.3" +name = "hyper" +version = "0.14.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9567389417feee6ce15dd6527a8a1ecac205ef62c2932bcf3d9f6fc5b78b414" +checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" dependencies = [ - "futures", - "rustc_version 0.4.1", -] - -[[package]] -name = "pin-project" -version = "1.1.10" + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2 0.3.27", + "http 0.2.12", + "http-body 0.4.6", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2 0.5.10", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" +checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" dependencies = [ - "pin-project-internal", + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "h2 0.4.13", + "http 1.4.0", + "http-body 1.0.1", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "pin-utils", + "smallvec", + "tokio", + "want", ] [[package]] -name = "pin-project-internal" -version = "1.1.10" +name = "hyper-named-pipe" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" +checksum = "73b7d8abf35697b81a825e386fc151e0d503e8cb5fcb93cc8669c376dfd6f278" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.114", + "hex", + "hyper 1.8.1", + "hyper-util", + "pin-project-lite", + "tokio", + "tower-service", + "winapi", ] [[package]] -name = "pin-project-lite" -version = "0.2.16" +name = "hyper-rustls" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +dependencies = [ + "futures-util", + "http 0.2.12", + "hyper 0.14.32", + "log", + "rustls 0.21.12", + "tokio", + "tokio-rustls 0.24.1", +] [[package]] -name = "pin-utils" -version = "0.1.0" +name = "hyper-rustls" +version = "0.27.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" +dependencies = [ + "http 1.4.0", + "hyper 1.8.1", + "hyper-util", + "log", + "rustls 0.23.36", + "rustls-native-certs", + "rustls-pki-types", + "tokio", + "tokio-rustls 0.26.4", + "tower-service", +] [[package]] -name = "pkcs8" -version = "0.10.2" +name = "hyper-tls" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ - "der", - "spki", + "bytes", + "http-body-util", + "hyper 1.8.1", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", ] [[package]] -name = "pkg-config" -version = "0.3.32" +name = "hyper-util" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-channel", + "futures-util", + "http 1.4.0", + "http-body 1.0.1", + "hyper 1.8.1", + "ipnet", + "libc", + "percent-encoding", + "pin-project-lite", + "socket2 0.6.2", + "tokio", + "tower-service", + "tracing", +] [[package]] -name = "png" -version = "0.18.0" +name = "hyperlocal" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97baced388464909d42d89643fe4361939af9b7ce7a31ee32a168f832a70f2a0" +checksum = "986c5ce3b994526b3cd75578e62554abd09f0899d6206de48b3e96ab34ccc8c7" dependencies = [ - "bitflags", - "crc32fast", - "fdeflate", - "flate2", - "miniz_oxide", + "hex", + "http-body-util", + "hyper 1.8.1", + "hyper-util", + "pin-project-lite", + "tokio", + "tower-service", ] [[package]] -name = "potential_utf" -version = "0.1.4" +name = "iana-time-zone" +version = "0.1.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" dependencies = [ - "zerovec", + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", ] [[package]] -name = "powerfmt" -version = "0.2.0" +name = "iana-time-zone-haiku" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] [[package]] -name = "ppv-lite86" -version = "0.2.21" +name = "icu_collections" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" dependencies = [ - "zerocopy", + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", ] [[package]] -name = "primitive-types" -version = "0.12.2" +name = "icu_locale_core" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" dependencies = [ - "fixed-hash", - "impl-codec", - "uint", + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", ] [[package]] -name = "proc-macro-crate" -version = "3.4.0" +name = "icu_normalizer" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" dependencies = [ - "toml_edit", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", ] [[package]] -name = "proc-macro-error-attr2" -version = "2.0.0" +name = "icu_normalizer_data" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" + +[[package]] +name = "icu_properties" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" dependencies = [ - "proc-macro2", - "quote", + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", ] [[package]] -name = "proc-macro-error2" -version = "2.0.1" +name = "icu_properties_data" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" + +[[package]] +name = "icu_provider" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" dependencies = [ - "proc-macro-error-attr2", - "proc-macro2", - "quote", - "syn 2.0.114", + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", ] [[package]] -name = "proc-macro2" -version = "1.0.106" +name = "id-arena" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" dependencies = [ - "unicode-ident", + "idna_adapter", + "smallvec", + "utf8_iter", ] [[package]] -name = "proptest" -version = "1.10.0" +name = "idna_adapter" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37566cb3fdacef14c0737f9546df7cfeadbfbc9fef10991038bf5015d0c80532" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" dependencies = [ - "bit-set", - "bit-vec", - "bitflags", + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "image" +version = "0.25.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6506c6c10786659413faa717ceebcb8f70731c0a60cbae39795fdf114519c1a" +dependencies = [ + "bytemuck", + "byteorder-lite", + "moxcms", "num-traits", - "rand 0.9.2", - "rand_chacha 0.9.0", - "rand_xorshift", + "png", + "tiff", +] + +[[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-trait-for-tuples" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "include_dir" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "923d117408f1e49d914f1a379a309cffe4f18c05cf4e3d12e613a15fc81bd0dd" +dependencies = [ + "include_dir_macros", +] + +[[package]] +name = "include_dir_macros" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cab85a7ed0bd5f0e76d93846e0147172bed2e2d3f859bcc33a8d9699cad1a75" +dependencies = [ + "proc-macro2", + "quote", +] + +[[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", + "serde", +] + +[[package]] +name = "indexmap" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +dependencies = [ + "equivalent", + "hashbrown 0.16.1", + "serde", + "serde_core", +] + +[[package]] +name = "indoc" +version = "2.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706" +dependencies = [ + "rustversion", +] + +[[package]] +name = "ingress-rpc" +version = "0.0.0" +dependencies = [ + "alloy-consensus", + "alloy-primitives", + "alloy-provider", + "alloy-signer-local", + "anyhow", + "async-trait", + "audit", + "axum", + "backon", + "base-bundles", + "base-reth-rpc-types", + "clap", + "jsonrpsee", + "metrics", + "metrics-derive", + "mockall", + "moka", + "op-alloy-consensus 0.22.4", + "op-alloy-network 0.22.4", + "op-revm", + "rdkafka", + "serde_json", + "tokio", + "tracing", + "url", + "utils", + "uuid", + "wiremock", +] + +[[package]] +name = "ingress-rpc-bin" +version = "0.0.0" +dependencies = [ + "alloy-provider", + "anyhow", + "audit", + "base-bundles", + "clap", + "dotenvy", + "ingress-rpc", + "jsonrpsee", + "op-alloy-network 0.22.4", + "rdkafka", + "tokio", + "tracing", + "utils", +] + +[[package]] +name = "instability" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357b7205c6cd18dd2c86ed312d1e70add149aea98e7ef72b9fdf0270e555c11d" +dependencies = [ + "darling 0.23.0", + "indoc", + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "ipnet" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" + +[[package]] +name = "iri-string" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" + +[[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 = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" + +[[package]] +name = "jni" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" +dependencies = [ + "cesu8", + "cfg-if", + "combine", + "jni-sys", + "log", + "thiserror 1.0.69", + "walkdir", + "windows-sys 0.45.0", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom 0.3.4", + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "jsonrpsee" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f3f48dc3e6b8bd21e15436c1ddd0bc22a6a54e8ec46fedd6adf3425f396ec6a" +dependencies = [ + "jsonrpsee-core", + "jsonrpsee-http-client", + "jsonrpsee-proc-macros", + "jsonrpsee-server", + "jsonrpsee-types", + "tokio", + "tracing", +] + +[[package]] +name = "jsonrpsee-core" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "316c96719901f05d1137f19ba598b5fe9c9bc39f4335f67f6be8613921946480" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http 1.4.0", + "http-body 1.0.1", + "http-body-util", + "jsonrpsee-types", + "parking_lot", + "pin-project", + "rand 0.9.2", + "rustc-hash", + "serde", + "serde_json", + "thiserror 2.0.18", + "tokio", + "tower", + "tracing", +] + +[[package]] +name = "jsonrpsee-http-client" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790bedefcec85321e007ff3af84b4e417540d5c87b3c9779b9e247d1bcc3dab8" +dependencies = [ + "base64 0.22.1", + "http-body 1.0.1", + "hyper 1.8.1", + "hyper-rustls 0.27.7", + "hyper-util", + "jsonrpsee-core", + "jsonrpsee-types", + "rustls 0.23.36", + "rustls-platform-verifier", + "serde", + "serde_json", + "thiserror 2.0.18", + "tokio", + "tower", + "url", +] + +[[package]] +name = "jsonrpsee-proc-macros" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2da3f8ab5ce1bb124b6d082e62dffe997578ceaf0aeb9f3174a214589dc00f07" +dependencies = [ + "heck", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "jsonrpsee-server" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c51b7c290bb68ce3af2d029648148403863b982f138484a73f02a9dd52dbd7f" +dependencies = [ + "futures-util", + "http 1.4.0", + "http-body 1.0.1", + "http-body-util", + "hyper 1.8.1", + "hyper-util", + "jsonrpsee-core", + "jsonrpsee-types", + "pin-project", + "route-recognizer", + "serde", + "serde_json", + "soketto", + "thiserror 2.0.18", + "tokio", + "tokio-stream", + "tokio-util", + "tower", + "tracing", +] + +[[package]] +name = "jsonrpsee-types" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc88ff4688e43cc3fa9883a8a95c6fa27aa2e76c96e610b737b6554d650d7fd5" +dependencies = [ + "http 1.4.0", + "serde", + "serde_json", + "thiserror 2.0.18", +] + +[[package]] +name = "jsonwebtoken" +version = "9.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a87cc7a48537badeae96744432de36f4be2b4a34a05a5ef32e9dd8a1c169dde" +dependencies = [ + "base64 0.22.1", + "js-sys", + "pem", + "ring", + "serde", + "serde_json", + "simple_asn1", +] + +[[package]] +name = "k256" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "once_cell", + "serdect", + "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.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b646a74e746cd25045aa0fd42f4f7f78aa6d119380182c7e63a5593c4ab8df6f" +dependencies = [ + "digest 0.10.7", + "sha3-asm", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + +[[package]] +name = "libc" +version = "0.2.181" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "459427e2af2b9c839b132acb702a1c654d95e10f8c326bfc2ad11310e458b1c5" + +[[package]] +name = "libloading" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" +dependencies = [ + "cfg-if", + "windows-link", +] + +[[package]] +name = "libm" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" + +[[package]] +name = "libredox" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" +dependencies = [ + "bitflags 2.10.0", + "libc", + "redox_syscall 0.7.1", +] + +[[package]] +name = "libz-sys" +version = "1.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15d118bbf3771060e7311cc7bb0545b01d08a8b4a7de949198dec1fa0ca1c0f7" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" + +[[package]] +name = "linux-raw-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" + +[[package]] +name = "litemap" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "lru" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" +dependencies = [ + "hashbrown 0.15.5", +] + +[[package]] +name = "lru" +version = "0.16.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1dc47f592c06f33f8e3aea9591776ec7c9f9e4124778ff8a3c3b87159f7e593" +dependencies = [ + "hashbrown 0.16.1", +] + +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + +[[package]] +name = "macro-string" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b27834086c65ec3f9387b096d66e99f221cf081c2b738042aa252bcd41204e3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "matchers" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" +dependencies = [ + "regex-automata", +] + +[[package]] +name = "matchit" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" + +[[package]] +name = "md-5" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +dependencies = [ + "cfg-if", + "digest 0.10.7", +] + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "mempool-rebroadcaster" +version = "0.0.0" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-primitives", + "alloy-provider", + "alloy-rpc-types", + "alloy-rpc-types-eth", + "alloy-trie", + "serde", + "serde_json", + "tokio", + "tracing", + "tracing-subscriber 0.3.22", +] + +[[package]] +name = "mempool-rebroadcaster-bin" +version = "0.1.0" +dependencies = [ + "clap", + "dotenvy", + "mempool-rebroadcaster", + "tokio", + "tracing", + "tracing-subscriber 0.3.22", +] + +[[package]] +name = "metrics" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d5312e9ba3771cfa961b585728215e3d972c950a3eed9252aa093d6301277e8" +dependencies = [ + "ahash", + "portable-atomic", +] + +[[package]] +name = "metrics-derive" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "161ab904c2c62e7bda0f7562bf22f96440ca35ff79e66c800cbac298f2f4f5ec" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "metrics-exporter-prometheus" +version = "0.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b166dea96003ee2531cf14833efedced545751d800f03535801d833313f8c15" +dependencies = [ + "base64 0.22.1", + "http-body-util", + "hyper 1.8.1", + "hyper-util", + "indexmap 2.13.0", + "ipnet", + "metrics", + "metrics-util", + "quanta", + "thiserror 2.0.18", + "tokio", + "tracing", +] + +[[package]] +name = "metrics-util" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdfb1365fea27e6dd9dc1dbc19f570198bc86914533ad639dae939635f096be4" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", + "hashbrown 0.16.1", + "metrics", + "quanta", + "rand 0.9.2", + "rand_xoshiro", + "sketches-ddsketch", +] + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "mio" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" +dependencies = [ + "libc", + "log", + "wasi", + "windows-sys 0.61.2", +] + +[[package]] +name = "mockall" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39a6bfcc6c8c7eed5ee98b9c3e33adc726054389233e201c95dab2d41a3839d2" +dependencies = [ + "cfg-if", + "downcast", + "fragile", + "mockall_derive", + "predicates", + "predicates-tree", +] + +[[package]] +name = "mockall_derive" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25ca3004c2efe9011bd4e461bd8256445052b9615405b4f7ea43fc8ca5c20898" +dependencies = [ + "cfg-if", + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "modular-bitfield" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a53d79ba8304ac1c4f9eb3b9d281f21f7be9d4626f72ce7df4ad8fbde4f38a74" +dependencies = [ + "modular-bitfield-impl", + "static_assertions", +] + +[[package]] +name = "modular-bitfield-impl" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a7d5f7076603ebc68de2dc6a650ec331a062a13abaa346975be747bbfa4b789" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "moka" +version = "0.12.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ac832c50ced444ef6be0767a008b02c106a909ba79d1d830501e94b96f6b7e" +dependencies = [ + "async-lock", + "crossbeam-channel", + "crossbeam-epoch", + "crossbeam-utils", + "equivalent", + "event-listener", + "futures-util", + "parking_lot", + "portable-atomic", + "smallvec", + "tagptr", + "uuid", +] + +[[package]] +name = "moxcms" +version = "0.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac9557c559cd6fc9867e122e20d2cbefc9ca29d80d027a8e39310920ed2f0a97" +dependencies = [ + "num-traits", + "pxfm", +] + +[[package]] +name = "native-tls" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe 0.1.6", + "openssl-sys", + "schannel", + "security-framework 2.11.1", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "nu-ansi-term" +version = "0.50.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "num" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[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-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-conv" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050" + +[[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-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "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.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "num_enum" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1207a7e20ad57b847bbddc6776b968420d38292bbfe2089accff5e19e82454c" +dependencies = [ + "num_enum_derive", + "rustversion", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "nybbles" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d49ff0c0d00d4a502b39df9af3a525e1efeb14b9dabb5bb83335284c1309210" +dependencies = [ + "alloy-rlp", + "cfg-if", + "proptest", + "ruint", + "serde", + "smallvec", +] + +[[package]] +name = "objc2" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c2599ce0ec54857b29ce62166b0ed9b4f6f1a70ccc9a71165b6154caca8c05" +dependencies = [ + "objc2-encode", +] + +[[package]] +name = "objc2-app-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c" +dependencies = [ + "bitflags 2.10.0", + "objc2", + "objc2-core-graphics", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" +dependencies = [ + "bitflags 2.10.0", + "dispatch2", + "objc2", +] + +[[package]] +name = "objc2-core-graphics" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807" +dependencies = [ + "bitflags 2.10.0", + "dispatch2", + "objc2", + "objc2-core-foundation", + "objc2-io-surface", +] + +[[package]] +name = "objc2-encode" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" + +[[package]] +name = "objc2-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" +dependencies = [ + "bitflags 2.10.0", + "objc2", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-io-surface" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180788110936d59bab6bd83b6060ffdfffb3b922ba1396b312ae795e1de9d81d" +dependencies = [ + "bitflags 2.10.0", + "objc2", + "objc2-core-foundation", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +dependencies = [ + "critical-section", + "portable-atomic", +] + +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + +[[package]] +name = "op-alloy" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9b8fee21003dd4f076563de9b9d26f8c97840157ef78593cd7f262c5ca99848" +dependencies = [ + "op-alloy-consensus 0.23.1", + "op-alloy-network 0.23.1", + "op-alloy-provider", + "op-alloy-rpc-types 0.23.1", + "op-alloy-rpc-types-engine", +] + +[[package]] +name = "op-alloy-consensus" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "726da827358a547be9f1e37c2a756b9e3729cb0350f43408164794b370cad8ae" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-network", + "alloy-primitives", + "alloy-rlp", + "alloy-rpc-types-eth", + "alloy-serde", + "derive_more", + "serde", + "thiserror 2.0.18", +] + +[[package]] +name = "op-alloy-consensus" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "736381a95471d23e267263cfcee9e1d96d30b9754a94a2819148f83379de8a86" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-network", + "alloy-primitives", + "alloy-rlp", + "alloy-rpc-types-eth", + "alloy-serde", + "derive_more", + "serde", + "thiserror 2.0.18", +] + +[[package]] +name = "op-alloy-flz" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a79f352fc3893dcd670172e615afef993a41798a1d3fc0db88a3e60ef2e70ecc" + +[[package]] +name = "op-alloy-network" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63f27e65be273ec8fcb0b6af0fd850b550979465ab93423705ceb3dfddbd2ab" +dependencies = [ + "alloy-consensus", + "alloy-network", + "alloy-primitives", + "alloy-provider", + "alloy-rpc-types-eth", + "alloy-signer", + "op-alloy-consensus 0.22.4", + "op-alloy-rpc-types 0.22.4", +] + +[[package]] +name = "op-alloy-network" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4034183dca6bff6632e7c24c92e75ff5f0eabb58144edb4d8241814851334d47" +dependencies = [ + "alloy-consensus", + "alloy-network", + "alloy-primitives", + "alloy-provider", + "alloy-rpc-types-eth", + "alloy-signer", + "op-alloy-consensus 0.23.1", + "op-alloy-rpc-types 0.23.1", +] + +[[package]] +name = "op-alloy-provider" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6753d90efbaa8ea8bcb89c1737408ca85fa60d7adb875049d3f382c063666f86" +dependencies = [ + "alloy-network", + "alloy-primitives", + "alloy-provider", + "alloy-rpc-types-engine", + "alloy-transport", + "async-trait", + "op-alloy-rpc-types-engine", +] + +[[package]] +name = "op-alloy-rpc-types" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "562dd4462562c41f9fdc4d860858c40e14a25df7f983ae82047f15f08fce4d19" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-network-primitives", + "alloy-primitives", + "alloy-rpc-types-eth", + "alloy-serde", + "derive_more", + "op-alloy-consensus 0.22.4", + "serde", + "serde_json", + "thiserror 2.0.18", +] + +[[package]] +name = "op-alloy-rpc-types" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd87c6b9e5b6eee8d6b76f41b04368dca0e9f38d83338e5b00e730c282098a4" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-network-primitives", + "alloy-primitives", + "alloy-rpc-types-eth", + "alloy-serde", + "derive_more", + "op-alloy-consensus 0.23.1", + "serde", + "serde_json", + "thiserror 2.0.18", +] + +[[package]] +name = "op-alloy-rpc-types-engine" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77727699310a18cdeed32da3928c709e2704043b6584ed416397d5da65694efc" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-primitives", + "alloy-rlp", + "alloy-rpc-types-engine", + "alloy-serde", + "derive_more", + "ethereum_ssz", + "ethereum_ssz_derive", + "op-alloy-consensus 0.23.1", + "serde", + "sha2", + "snap", + "thiserror 2.0.18", +] + +[[package]] +name = "op-revm" +version = "15.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79c92b75162c2ed1661849fa51683b11254a5b661798360a2c24be918edafd40" +dependencies = [ + "auto_impl", + "revm", + "serde", +] + +[[package]] +name = "openssl" +version = "0.10.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328" +dependencies = [ + "bitflags 2.10.0", + "cfg-if", + "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.115", +] + +[[package]] +name = "openssl-probe" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" + +[[package]] +name = "openssl-probe" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" + +[[package]] +name = "openssl-src" +version = "300.5.5+3.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f1787d533e03597a7934fd0a765f0d28e94ecc5fb7789f8053b1e699a56f709" +dependencies = [ + "cc", +] + +[[package]] +name = "openssl-sys" +version = "0.9.111" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321" +dependencies = [ + "cc", + "libc", + "openssl-src", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "opentelemetry" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b84bcd6ae87133e903af7ef497404dda70c60d0ea14895fc8a5e6722754fc2a0" +dependencies = [ + "futures-core", + "futures-sink", + "js-sys", + "pin-project-lite", + "thiserror 2.0.18", + "tracing", +] + +[[package]] +name = "opentelemetry-http" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7a6d09a73194e6b66df7c8f1b680f156d916a1a942abf2de06823dd02b7855d" +dependencies = [ + "async-trait", + "bytes", + "http 1.4.0", + "opentelemetry", +] + +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "outref" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a80800c0488c3a21695ea981a54918fbb37abf04f4d0720c453632255e2ff0e" + +[[package]] +name = "p256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + +[[package]] +name = "parity-scale-codec" +version = "3.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799781ae679d79a948e13d4824a40970bfa500058d245760dd857301059810fa" +dependencies = [ + "arrayvec", + "bitvec", + "byte-slice-cast", + "const_format", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "rustversion", + "serde", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34b4653168b563151153c9e4c08ebed57fb8262bebfa79711552fa983c623e7a" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.5.18", + "smallvec", + "windows-link", +] + +[[package]] +name = "parse-display" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "914a1c2265c98e2446911282c6ac86d8524f495792c38c5bd884f80499c7538a" +dependencies = [ + "parse-display-derive", + "regex", + "regex-syntax", +] + +[[package]] +name = "parse-display-derive" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ae7800a4c974efd12df917266338e79a7a74415173caf7e70aa0a0707345281" +dependencies = [ + "proc-macro2", + "quote", + "regex", + "regex-syntax", + "structmeta", + "syn 2.0.115", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pem" +version = "3.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d30c53c26bc5b31a98cd02d20f25a7c8567146caf63ed593a9d87b2775291be" +dependencies = [ + "base64 0.22.1", + "serde_core", +] + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "pest" +version = "2.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0848c601009d37dfa3430c4666e147e49cdcf1b92ecd3e63657d8a5f19da662" +dependencies = [ + "memchr", + "ucd-trie", +] + +[[package]] +name = "pharos" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9567389417feee6ce15dd6527a8a1ecac205ef62c2932bcf3d9f6fc5b78b414" +dependencies = [ + "futures", + "rustc_version 0.4.1", +] + +[[package]] +name = "phf" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" +dependencies = [ + "phf_macros", + "phf_shared", + "serde", +] + +[[package]] +name = "phf_generator" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737" +dependencies = [ + "fastrand", + "phf_shared", +] + +[[package]] +name = "phf_macros" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812f032b54b1e759ccd5f8b6677695d5268c588701effba24601f6932f8269ef" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "phf_shared" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e57fef6bc5981e38c2ce2d63bfa546861309f875b8a75f092d1d54ae2d64f266" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pin-project" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[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.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "png" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97baced388464909d42d89643fe4361939af9b7ce7a31ee32a168f832a70f2a0" +dependencies = [ + "bitflags 2.10.0", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + +[[package]] +name = "portable-atomic" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" + +[[package]] +name = "potential_utf" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" +dependencies = [ + "zerovec", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "predicates" +version = "3.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ada8f2932f28a27ee7b70dd6c1c39ea0675c55a36879ab92f3a715eaa1e63cfe" +dependencies = [ + "anstyle", + "predicates-core", +] + +[[package]] +name = "predicates-core" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cad38746f3166b4031b1a0d39ad9f954dd291e7854fcc0eed52ee41a0b50d144" + +[[package]] +name = "predicates-tree" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0de1b847b39c8131db0467e9df1ff60e6d0562ab8e9a16e568ad0fdb372e2f2" +dependencies = [ + "predicates-core", + "termtree", +] + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn 2.0.115", +] + +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve", +] + +[[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", + "uint", +] + +[[package]] +name = "proc-macro-crate" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "proptest" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37566cb3fdacef14c0737f9546df7cfeadbfbc9fef10991038bf5015d0c80532" +dependencies = [ + "bit-set", + "bit-vec", + "bitflags 2.10.0", + "num-traits", + "rand 0.9.2", + "rand_chacha 0.9.0", + "rand_xorshift", + "regex-syntax", + "rusty-fork", + "tempfile", + "unarray", +] + +[[package]] +name = "pxfm" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7186d3822593aa4393561d186d1393b3923e9d6163d3fbfd6e825e3e6cf3e6a8" +dependencies = [ + "num-traits", +] + +[[package]] +name = "quanta" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3ab5a9d756f0d97bdc89019bd2e4ea098cf9cde50ee7564dde6b81ccc8f06c7" +dependencies = [ + "crossbeam-utils", + "libc", + "once_cell", + "raw-cpuid", + "wasi", + "web-sys", + "winapi", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quick-error" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" + +[[package]] +name = "quinn" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" +dependencies = [ + "bytes", + "cfg_aliases", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls 0.23.36", + "socket2 0.6.2", + "thiserror 2.0.18", + "tokio", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-proto" +version = "0.11.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31" +dependencies = [ + "bytes", + "getrandom 0.3.4", + "lru-slab", + "rand 0.9.2", + "ring", + "rustc-hash", + "rustls 0.23.36", + "rustls-pki-types", + "slab", + "thiserror 2.0.18", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2 0.6.2", + "tracing", + "windows-sys 0.60.2", +] + +[[package]] +name = "quote" +version = "1.0.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[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 0.3.1", + "rand_core 0.6.4", + "serde", +] + +[[package]] +name = "rand" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.5", + "serde", +] + +[[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 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.5", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.17", +] + +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom 0.3.4", + "serde", +] + +[[package]] +name = "rand_xorshift" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" +dependencies = [ + "rand_core 0.9.5", +] + +[[package]] +name = "rand_xoshiro" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f703f4665700daf5512dcca5f43afa6af89f09db47fb56be587f80636bda2d41" +dependencies = [ + "rand_core 0.9.5", +] + +[[package]] +name = "rapidhash" +version = "4.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84816e4c99c467e92cf984ee6328caa976dfecd33a673544489d79ca2caaefe5" +dependencies = [ + "rand 0.9.2", + "rustversion", +] + +[[package]] +name = "ratatui" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eabd94c2f37801c20583fc49dd5cd6b0ba68c716787c2dd6ed18571e1e63117b" +dependencies = [ + "bitflags 2.10.0", + "cassowary", + "compact_str", + "crossterm", + "indoc", + "instability", + "itertools 0.13.0", + "lru 0.12.5", + "paste", + "strum 0.26.3", + "unicode-segmentation", + "unicode-truncate", + "unicode-width 0.2.0", +] + +[[package]] +name = "raw-cpuid" +version = "11.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "498cd0dc59d73224351ee52a95fee0f1a617a2eae0e7d9d720cc622c73a54186" +dependencies = [ + "bitflags 2.10.0", +] + +[[package]] +name = "rayon" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "rdkafka" +version = "0.37.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14b52c81ac3cac39c9639b95c20452076e74b8d9a71bc6fc4d83407af2ea6fff" +dependencies = [ + "futures-channel", + "futures-util", + "libc", + "log", + "rdkafka-sys", + "serde", + "serde_derive", + "serde_json", + "slab", + "tokio", +] + +[[package]] +name = "rdkafka-sys" +version = "4.10.0+2.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e234cf318915c1059d4921ef7f75616b5219b10b46e9f3a511a15eb4b56a3f77" +dependencies = [ + "libc", + "libz-sys", + "num_enum", + "openssl-sys", + "pkg-config", + "zstd-sys", +] + +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags 2.10.0", +] + +[[package]] +name = "redox_syscall" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35985aa610addc02e24fc232012c86fd11f14111180f902b67e2d5331f8ebf2b" +dependencies = [ + "bitflags 2.10.0", +] + +[[package]] +name = "redox_users" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" +dependencies = [ + "getrandom 0.2.17", + "libredox", + "thiserror 2.0.18", +] + +[[package]] +name = "ref-cast" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "regex" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", "regex-syntax", - "rusty-fork", - "tempfile", - "unarray", ] [[package]] -name = "pxfm" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7186d3822593aa4393561d186d1393b3923e9d6163d3fbfd6e825e3e6cf3e6a8" +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-lite" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab834c73d247e67f4fae452806d17d3c7501756d98c8808d7c9c7aa7d18f973" + +[[package]] +name = "regex-syntax" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a96887878f22d7bad8a3b6dc5b7440e0ada9a245242924394987b21cf2210a4c" + +[[package]] +name = "reqwest" +version = "0.12.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-core", + "http 1.4.0", + "http-body 1.0.1", + "http-body-util", + "hyper 1.8.1", + "hyper-rustls 0.27.7", + "hyper-tls", + "hyper-util", + "js-sys", + "log", + "native-tls", + "percent-encoding", + "pin-project-lite", + "quinn", + "rustls 0.23.36", + "rustls-native-certs", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tokio-native-tls", + "tokio-rustls 0.26.4", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "reth-chain-state" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-primitives", + "derive_more", + "metrics", + "parking_lot", + "pin-project", + "reth-chainspec", + "reth-errors", + "reth-ethereum-primitives", + "reth-execution-types", + "reth-metrics", + "reth-primitives-traits", + "reth-storage-api", + "reth-trie", + "revm-database", + "tokio", + "tokio-stream", + "tracing", +] + +[[package]] +name = "reth-chainspec" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" +dependencies = [ + "alloy-chains", + "alloy-consensus", + "alloy-eips", + "alloy-evm", + "alloy-genesis", + "alloy-primitives", + "alloy-trie", + "auto_impl", + "derive_more", + "reth-ethereum-forks", + "reth-network-peers", + "reth-primitives-traits", + "serde_json", +] + +[[package]] +name = "reth-codecs" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-genesis", + "alloy-primitives", + "alloy-trie", + "bytes", + "modular-bitfield", + "op-alloy-consensus 0.23.1", + "reth-codecs-derive", + "reth-zstd-compressors", + "serde", +] + +[[package]] +name = "reth-codecs-derive" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "reth-consensus" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" +dependencies = [ + "alloy-consensus", + "alloy-primitives", + "auto_impl", + "reth-execution-types", + "reth-primitives-traits", + "thiserror 2.0.18", +] + +[[package]] +name = "reth-consensus-common" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "reth-chainspec", + "reth-consensus", + "reth-primitives-traits", +] + +[[package]] +name = "reth-db-models" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" +dependencies = [ + "alloy-eips", + "alloy-primitives", + "bytes", + "reth-primitives-traits", + "serde", +] + +[[package]] +name = "reth-errors" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" +dependencies = [ + "reth-consensus", + "reth-execution-errors", + "reth-storage-errors", + "thiserror 2.0.18", +] + +[[package]] +name = "reth-eth-wire-types" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" +dependencies = [ + "alloy-chains", + "alloy-consensus", + "alloy-eips", + "alloy-hardforks", + "alloy-primitives", + "alloy-rlp", + "bytes", + "derive_more", + "reth-chainspec", + "reth-codecs-derive", + "reth-ethereum-primitives", + "reth-primitives-traits", + "serde", + "thiserror 2.0.18", +] + +[[package]] +name = "reth-ethereum-forks" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" +dependencies = [ + "alloy-eip2124", + "alloy-hardforks", + "alloy-primitives", + "auto_impl", + "once_cell", + "rustc-hash", +] + +[[package]] +name = "reth-ethereum-primitives" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-primitives", + "alloy-rlp", + "alloy-rpc-types-eth", + "alloy-serde", + "reth-primitives-traits", + "reth-zstd-compressors", + "serde", + "serde_with", +] + +[[package]] +name = "reth-evm" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-evm", + "alloy-primitives", + "auto_impl", + "derive_more", + "futures-util", + "rayon", + "reth-execution-errors", + "reth-execution-types", + "reth-primitives-traits", + "reth-storage-api", + "reth-storage-errors", + "reth-trie-common", + "revm", +] + +[[package]] +name = "reth-execution-errors" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" +dependencies = [ + "alloy-evm", + "alloy-primitives", + "alloy-rlp", + "nybbles", + "reth-storage-errors", + "thiserror 2.0.18", +] + +[[package]] +name = "reth-execution-types" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-evm", + "alloy-primitives", + "derive_more", + "reth-ethereum-primitives", + "reth-primitives-traits", + "reth-trie-common", + "revm", + "serde", + "serde_with", +] + +[[package]] +name = "reth-fs-util" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" +dependencies = [ + "serde", + "serde_json", + "thiserror 2.0.18", +] + +[[package]] +name = "reth-metrics" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" +dependencies = [ + "metrics", + "metrics-derive", +] + +[[package]] +name = "reth-net-banlist" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" +dependencies = [ + "alloy-primitives", + "ipnet", +] + +[[package]] +name = "reth-network-api" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" +dependencies = [ + "alloy-consensus", + "alloy-primitives", + "alloy-rpc-types-admin", + "alloy-rpc-types-eth", + "auto_impl", + "derive_more", + "enr", + "futures", + "reth-eth-wire-types", + "reth-ethereum-forks", + "reth-network-p2p", + "reth-network-peers", + "reth-network-types", + "reth-tokio-util", + "thiserror 2.0.18", + "tokio", + "tokio-stream", +] + +[[package]] +name = "reth-network-p2p" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-primitives", + "auto_impl", + "derive_more", + "futures", + "reth-consensus", + "reth-eth-wire-types", + "reth-ethereum-primitives", + "reth-network-peers", + "reth-network-types", + "reth-primitives-traits", + "reth-storage-errors", + "tokio", + "tracing", +] + +[[package]] +name = "reth-network-peers" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "secp256k1 0.30.0", + "serde_with", + "thiserror 2.0.18", + "url", +] + +[[package]] +name = "reth-network-types" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" +dependencies = [ + "alloy-eip2124", + "reth-net-banlist", + "reth-network-peers", + "serde_json", + "tracing", +] + +[[package]] +name = "reth-optimism-chainspec" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" +dependencies = [ + "alloy-chains", + "alloy-consensus", + "alloy-eips", + "alloy-genesis", + "alloy-hardforks", + "alloy-primitives", + "derive_more", + "miniz_oxide", + "op-alloy-consensus 0.23.1", + "op-alloy-rpc-types 0.23.1", + "reth-chainspec", + "reth-ethereum-forks", + "reth-network-peers", + "reth-optimism-forks", + "reth-optimism-primitives", + "reth-primitives-traits", + "serde", + "serde_json", + "thiserror 2.0.18", +] + +[[package]] +name = "reth-optimism-consensus" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-primitives", + "alloy-trie", + "reth-chainspec", + "reth-consensus", + "reth-consensus-common", + "reth-execution-types", + "reth-optimism-chainspec", + "reth-optimism-forks", + "reth-optimism-primitives", + "reth-primitives-traits", + "reth-storage-api", + "reth-storage-errors", + "reth-trie-common", + "revm", + "thiserror 2.0.18", + "tracing", +] + +[[package]] +name = "reth-optimism-evm" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-evm", + "alloy-op-evm", + "alloy-primitives", + "op-alloy-consensus 0.23.1", + "op-alloy-rpc-types-engine", + "op-revm", + "reth-chainspec", + "reth-evm", + "reth-execution-errors", + "reth-execution-types", + "reth-optimism-chainspec", + "reth-optimism-consensus", + "reth-optimism-forks", + "reth-optimism-primitives", + "reth-primitives-traits", + "reth-storage-errors", + "revm", + "thiserror 2.0.18", +] + +[[package]] +name = "reth-optimism-forks" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" +dependencies = [ + "alloy-op-hardforks", + "alloy-primitives", + "once_cell", + "reth-ethereum-forks", +] + +[[package]] +name = "reth-optimism-primitives" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-primitives", + "alloy-rlp", + "op-alloy-consensus 0.23.1", + "reth-primitives-traits", + "serde", + "serde_with", +] + +[[package]] +name = "reth-primitives-traits" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-genesis", + "alloy-primitives", + "alloy-rlp", + "alloy-rpc-types-eth", + "alloy-trie", + "auto_impl", + "bytes", + "derive_more", + "once_cell", + "op-alloy-consensus 0.23.1", + "reth-codecs", + "revm-bytecode", + "revm-primitives", + "revm-state", + "secp256k1 0.30.0", + "serde", + "serde_with", + "thiserror 2.0.18", +] + +[[package]] +name = "reth-prune-types" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" +dependencies = [ + "alloy-primitives", + "derive_more", + "serde", + "strum 0.27.2", + "thiserror 2.0.18", +] + +[[package]] +name = "reth-revm" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" +dependencies = [ + "alloy-primitives", + "reth-primitives-traits", + "reth-storage-api", + "reth-storage-errors", + "revm", +] + +[[package]] +name = "reth-rpc-convert" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" +dependencies = [ + "alloy-consensus", + "alloy-evm", + "alloy-json-rpc", + "alloy-network", + "alloy-primitives", + "alloy-rpc-types-eth", + "alloy-signer", + "auto_impl", + "dyn-clone", + "jsonrpsee-types", + "reth-ethereum-primitives", + "reth-evm", + "reth-primitives-traits", + "thiserror 2.0.18", +] + +[[package]] +name = "reth-rpc-eth-types" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-evm", + "alloy-network", + "alloy-primitives", + "alloy-rpc-client", + "alloy-rpc-types-eth", + "alloy-sol-types", + "alloy-transport", + "derive_more", + "futures", + "itertools 0.14.0", + "jsonrpsee-core", + "jsonrpsee-types", + "metrics", + "rand 0.9.2", + "reqwest", + "reth-chain-state", + "reth-chainspec", + "reth-errors", + "reth-ethereum-primitives", + "reth-evm", + "reth-execution-types", + "reth-metrics", + "reth-primitives-traits", + "reth-revm", + "reth-rpc-convert", + "reth-rpc-server-types", + "reth-storage-api", + "reth-tasks", + "reth-transaction-pool", + "reth-trie", + "revm", + "revm-inspectors", + "schnellru", + "serde", + "thiserror 2.0.18", + "tokio", + "tokio-stream", + "tracing", + "url", +] + +[[package]] +name = "reth-rpc-server-types" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" +dependencies = [ + "alloy-eips", + "alloy-primitives", + "alloy-rpc-types-engine", + "jsonrpsee-core", + "jsonrpsee-types", + "reth-errors", + "reth-network-api", + "serde", + "strum 0.27.2", +] + +[[package]] +name = "reth-stages-types" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" +dependencies = [ + "alloy-primitives", + "bytes", + "reth-trie-common", + "serde", +] + +[[package]] +name = "reth-static-file-types" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" dependencies = [ - "num-traits", + "alloy-primitives", + "derive_more", + "fixed-map", + "serde", + "strum 0.27.2", ] [[package]] -name = "quick-error" -version = "1.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" +name = "reth-storage-api" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-primitives", + "alloy-rpc-types-engine", + "auto_impl", + "reth-chainspec", + "reth-db-models", + "reth-ethereum-primitives", + "reth-execution-types", + "reth-primitives-traits", + "reth-prune-types", + "reth-stages-types", + "reth-storage-errors", + "reth-trie-common", + "revm-database", + "serde_json", +] [[package]] -name = "quick-error" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" +name = "reth-storage-errors" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" +dependencies = [ + "alloy-eips", + "alloy-primitives", + "alloy-rlp", + "derive_more", + "reth-primitives-traits", + "reth-prune-types", + "reth-static-file-types", + "revm-database-interface", + "revm-state", + "thiserror 2.0.18", +] [[package]] -name = "quote" -version = "1.0.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" +name = "reth-tasks" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" dependencies = [ - "proc-macro2", + "auto_impl", + "dyn-clone", + "futures-util", + "metrics", + "reth-metrics", + "thiserror 2.0.18", + "tokio", + "tracing", + "tracing-futures", ] [[package]] -name = "r-efi" -version = "5.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" +name = "reth-tokio-util" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" +dependencies = [ + "tokio", + "tokio-stream", + "tracing", +] [[package]] -name = "radium" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" +name = "reth-transaction-pool" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-primitives", + "alloy-rlp", + "aquamarine", + "auto_impl", + "bitflags 2.10.0", + "futures-util", + "metrics", + "parking_lot", + "pin-project", + "reth-chain-state", + "reth-chainspec", + "reth-eth-wire-types", + "reth-ethereum-primitives", + "reth-execution-types", + "reth-fs-util", + "reth-metrics", + "reth-primitives-traits", + "reth-storage-api", + "reth-tasks", + "revm-interpreter", + "revm-primitives", + "rustc-hash", + "schnellru", + "serde", + "serde_json", + "smallvec", + "thiserror 2.0.18", + "tokio", + "tokio-stream", + "tracing", +] [[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +name = "reth-trie" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" dependencies = [ - "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.4", - "serde", + "alloy-consensus", + "alloy-eips", + "alloy-primitives", + "alloy-rlp", + "alloy-trie", + "auto_impl", + "itertools 0.14.0", + "reth-execution-errors", + "reth-primitives-traits", + "reth-stages-types", + "reth-storage-errors", + "reth-trie-common", + "reth-trie-sparse", + "revm-database", + "tracing", ] [[package]] -name = "rand" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +name = "reth-trie-common" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" dependencies = [ - "rand_chacha 0.9.0", - "rand_core 0.9.5", + "alloy-consensus", + "alloy-primitives", + "alloy-rlp", + "alloy-rpc-types-eth", + "alloy-serde", + "alloy-trie", + "arrayvec", + "bytes", + "derive_more", + "itertools 0.14.0", + "nybbles", + "rayon", + "reth-primitives-traits", + "revm-database", "serde", + "serde_with", ] [[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +name = "reth-trie-sparse" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" dependencies = [ - "ppv-lite86", - "rand_core 0.6.4", + "alloy-primitives", + "alloy-rlp", + "alloy-trie", + "auto_impl", + "reth-execution-errors", + "reth-primitives-traits", + "reth-trie-common", + "smallvec", + "tracing", ] [[package]] -name = "rand_chacha" -version = "0.9.0" +name = "reth-zstd-compressors" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" +dependencies = [ + "zstd", +] + +[[package]] +name = "revm" +version = "34.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +checksum = "c2aabdebaa535b3575231a88d72b642897ae8106cf6b0d12eafc6bfdf50abfc7" dependencies = [ - "ppv-lite86", - "rand_core 0.9.5", + "revm-bytecode", + "revm-context", + "revm-context-interface", + "revm-database", + "revm-database-interface", + "revm-handler", + "revm-inspector", + "revm-interpreter", + "revm-precompile", + "revm-primitives", + "revm-state", ] [[package]] -name = "rand_core" -version = "0.6.4" +name = "revm-bytecode" +version = "8.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +checksum = "74d1e5c1eaa44d39d537f668bc5c3409dc01e5c8be954da6c83370bbdf006457" dependencies = [ - "getrandom 0.2.17", + "bitvec", + "phf", + "revm-primitives", + "serde", ] [[package]] -name = "rand_core" -version = "0.9.5" +name = "revm-context" +version = "13.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +checksum = "892ff3e6a566cf8d72ffb627fdced3becebbd9ba64089c25975b9b028af326a5" dependencies = [ - "getrandom 0.3.4", + "bitvec", + "cfg-if", + "derive-where", + "revm-bytecode", + "revm-context-interface", + "revm-database-interface", + "revm-primitives", + "revm-state", "serde", ] [[package]] -name = "rand_xorshift" -version = "0.4.0" +name = "revm-context-interface" +version = "14.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" +checksum = "57f61cc6d23678c4840af895b19f8acfbbd546142ec8028b6526c53cc1c16c98" dependencies = [ - "rand_core 0.9.5", + "alloy-eip2930", + "alloy-eip7702", + "auto_impl", + "either", + "revm-database-interface", + "revm-primitives", + "revm-state", + "serde", ] [[package]] -name = "rapidhash" -version = "4.2.2" +name = "revm-database" +version = "10.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71ec30b38a417407efe7676bad0ca6b78f995f810185ece9af3bd5dc561185a9" +checksum = "529528d0b05fe646be86223032c3e77aa8b05caa2a35447d538c55965956a511" dependencies = [ - "rustversion", + "alloy-eips", + "revm-bytecode", + "revm-database-interface", + "revm-primitives", + "revm-state", + "serde", ] [[package]] -name = "ratatui" -version = "0.29.0" +name = "revm-database-interface" +version = "9.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eabd94c2f37801c20583fc49dd5cd6b0ba68c716787c2dd6ed18571e1e63117b" +checksum = "b7bf93ac5b91347c057610c0d96e923db8c62807e03f036762d03e981feddc1d" dependencies = [ - "bitflags", - "cassowary", - "compact_str", - "crossterm", - "indoc", - "instability", - "itertools 0.13.0", - "lru 0.12.5", - "paste", - "strum 0.26.3", - "unicode-segmentation", - "unicode-truncate", - "unicode-width 0.2.0", + "auto_impl", + "either", + "revm-primitives", + "revm-state", + "serde", + "thiserror 2.0.18", ] [[package]] -name = "redox_syscall" -version = "0.5.18" +name = "revm-handler" +version = "15.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +checksum = "0cd0e43e815a85eded249df886c4badec869195e70cdd808a13cfca2794622d2" dependencies = [ - "bitflags", + "auto_impl", + "derive-where", + "revm-bytecode", + "revm-context", + "revm-context-interface", + "revm-database-interface", + "revm-interpreter", + "revm-precompile", + "revm-primitives", + "revm-state", + "serde", ] [[package]] -name = "redox_users" -version = "0.5.2" +name = "revm-inspector" +version = "15.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" +checksum = "4f3ccad59db91ef93696536a0dbaf2f6f17cfe20d4d8843ae118edb7e97947ef" dependencies = [ - "getrandom 0.2.17", - "libredox", - "thiserror", + "auto_impl", + "either", + "revm-context", + "revm-database-interface", + "revm-handler", + "revm-interpreter", + "revm-primitives", + "revm-state", + "serde", + "serde_json", ] [[package]] -name = "ref-cast" -version = "1.0.25" +name = "revm-inspectors" +version = "0.34.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" +checksum = "6e435414e9de50a1b930da602067c76365fea2fea11e80ceb50783c94ddd127f" dependencies = [ - "ref-cast-impl", + "alloy-primitives", + "alloy-rpc-types-eth", + "alloy-rpc-types-trace", + "alloy-sol-types", + "anstyle", + "colorchoice", + "revm", + "serde", + "serde_json", + "thiserror 2.0.18", ] [[package]] -name = "ref-cast-impl" -version = "1.0.25" +name = "revm-interpreter" +version = "32.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" +checksum = "11406408597bc249392d39295831c4b641b3a6f5c471a7c41104a7a1e3564c07" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.114", + "revm-bytecode", + "revm-context-interface", + "revm-primitives", + "revm-state", + "serde", ] [[package]] -name = "regex-automata" -version = "0.4.14" +name = "revm-precompile" +version = "32.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +checksum = "50c1285c848d240678bf69cb0f6179ff5a4aee6fc8e921d89708087197a0aff3" dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", + "ark-bls12-381", + "ark-bn254", + "ark-ec", + "ark-ff 0.5.0", + "ark-serialize 0.5.0", + "arrayref", + "aurora-engine-modexp", + "c-kzg", + "cfg-if", + "k256", + "p256", + "revm-primitives", + "ripemd", + "secp256k1 0.31.1", + "sha2", ] [[package]] -name = "regex-syntax" -version = "0.8.9" +name = "revm-primitives" +version = "22.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a96887878f22d7bad8a3b6dc5b7440e0ada9a245242924394987b21cf2210a4c" +checksum = "ba580c56a8ec824a64f8a1683577876c2e1dbe5247044199e9b881421ad5dcf9" +dependencies = [ + "alloy-primitives", + "num_enum", + "once_cell", + "serde", +] [[package]] -name = "reqwest" -version = "0.12.28" +name = "revm-state" +version = "9.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" +checksum = "311720d4f0f239b041375e7ddafdbd20032a33b7bae718562ea188e188ed9fd3" dependencies = [ - "base64", - "bytes", - "futures-core", - "http", - "http-body", - "http-body-util", - "hyper", - "hyper-tls", - "hyper-util", - "js-sys", - "log", - "native-tls", - "percent-encoding", - "pin-project-lite", - "rustls-pki-types", + "alloy-eip7928", + "bitflags 2.10.0", + "revm-bytecode", + "revm-primitives", "serde", - "serde_json", - "serde_urlencoded", - "sync_wrapper", - "tokio", - "tokio-native-tls", - "tower", - "tower-http", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", ] [[package]] @@ -3677,6 +7027,15 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "ripemd" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" +dependencies = [ + "digest 0.10.7", +] + [[package]] name = "rlp" version = "0.5.2" @@ -3687,6 +7046,12 @@ dependencies = [ "rustc-hex", ] +[[package]] +name = "route-recognizer" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afab94fb28594581f62d981211a9a4d53cc8130bbcbbb89a0440d9b8e81a7746" + [[package]] name = "ruint" version = "1.17.2" @@ -3726,6 +7091,9 @@ name = "rustc-hash" version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" +dependencies = [ + "rand 0.8.5", +] [[package]] name = "rustc-hex" @@ -3757,7 +7125,7 @@ version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags", + "bitflags 2.10.0", "errno", "libc", "linux-raw-sys 0.4.15", @@ -3770,41 +7138,116 @@ version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" dependencies = [ - "bitflags", + "bitflags 2.10.0", "errno", "libc", "linux-raw-sys 0.11.0", "windows-sys 0.61.2", ] +[[package]] +name = "rustls" +version = "0.21.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" +dependencies = [ + "log", + "ring", + "rustls-webpki 0.101.7", + "sct", +] + [[package]] name = "rustls" version = "0.23.36" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c665f33d38cea657d9614f766881e4d510e0eda4239891eea56b4cadcf01801b" dependencies = [ + "aws-lc-rs", + "log", "once_cell", + "ring", "rustls-pki-types", - "rustls-webpki", + "rustls-webpki 0.103.9", "subtle", "zeroize", ] +[[package]] +name = "rustls-native-certs" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" +dependencies = [ + "openssl-probe 0.2.1", + "rustls-pki-types", + "schannel", + "security-framework 3.5.1", +] + +[[package]] +name = "rustls-pemfile" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "rustls-pki-types" version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" dependencies = [ + "web-time", "zeroize", ] +[[package]] +name = "rustls-platform-verifier" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19787cda76408ec5404443dc8b31795c87cd8fec49762dc75fa727740d34acc1" +dependencies = [ + "core-foundation 0.10.1", + "core-foundation-sys", + "jni", + "log", + "once_cell", + "rustls 0.23.36", + "rustls-native-certs", + "rustls-platform-verifier-android", + "rustls-webpki 0.103.9", + "security-framework 3.5.1", + "security-framework-sys", + "webpki-root-certs 0.26.11", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustls-platform-verifier-android" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" + +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "rustls-webpki" version = "0.103.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53" dependencies = [ + "aws-lc-rs", "ring", "rustls-pki-types", "untrusted", @@ -3830,9 +7273,18 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.22" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + +[[package]] +name = "same-file" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a50f4cf475b65d88e057964e0e9bb1f0aa9bbb2036dc65c64596b42932536984" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] [[package]] name = "schannel" @@ -3867,12 +7319,33 @@ dependencies = [ "serde_json", ] +[[package]] +name = "schnellru" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "356285bbf17bea63d9e52e96bd18f039672ac92b55b8cb997d6162a2a37d1649" +dependencies = [ + "ahash", + "cfg-if", + "hashbrown 0.13.2", +] + [[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "sec1" version = "0.7.3" @@ -3896,10 +7369,21 @@ checksum = "b50c5943d326858130af85e049f2661ba3c78b26589b8ab98e65e80ae44a1252" dependencies = [ "bitcoin_hashes", "rand 0.8.5", - "secp256k1-sys", + "secp256k1-sys 0.10.1", "serde", ] +[[package]] +name = "secp256k1" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c3c81b43dc2d8877c216a3fccf76677ee1ebccd429566d3e67447290d0c42b2" +dependencies = [ + "bitcoin_hashes", + "rand 0.9.2", + "secp256k1-sys 0.11.0", +] + [[package]] name = "secp256k1-sys" version = "0.10.1" @@ -3909,14 +7393,36 @@ dependencies = [ "cc", ] +[[package]] +name = "secp256k1-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcb913707158fadaf0d8702c2db0e857de66eb003ccfdda5924b5f5ac98efb38" +dependencies = [ + "cc", +] + [[package]] name = "security-framework" version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags", - "core-foundation", + "bitflags 2.10.0", + "core-foundation 0.9.4", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework" +version = "3.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef" +dependencies = [ + "bitflags 2.10.0", + "core-foundation 0.10.1", "core-foundation-sys", "libc", "security-framework-sys", @@ -3989,7 +7495,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.115", ] [[package]] @@ -3998,6 +7504,7 @@ version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ + "indexmap 2.13.0", "itoa", "memchr", "serde", @@ -4005,6 +7512,28 @@ dependencies = [ "zmij", ] +[[package]] +name = "serde_path_to_error" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457" +dependencies = [ + "itoa", + "serde", + "serde_core", +] + +[[package]] +name = "serde_repr" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -4023,7 +7552,7 @@ version = "3.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fa237f2807440d238e0364a218270b98f767a00d3dada77b1c53ae88940e2e7" dependencies = [ - "base64", + "base64 0.22.1", "chrono", "hex", "indexmap 1.9.3", @@ -4045,7 +7574,7 @@ dependencies = [ "darling 0.21.3", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.115", ] [[package]] @@ -4082,6 +7611,12 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "sha1_smol" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d" + [[package]] name = "sha2" version = "0.10.9" @@ -4142,6 +7677,7 @@ dependencies = [ "cadence", "tokio", "tracing", + "tracing-subscriber 0.3.22", ] [[package]] @@ -4153,7 +7689,7 @@ dependencies = [ "sidecrush", "tokio", "tracing", - "tracing-subscriber", + "tracing-subscriber 0.3.22", ] [[package]] @@ -4211,10 +7747,22 @@ checksum = "297f631f50729c8c99b84667867963997ec0b50f32b2a7dbcab828ef0541e8bb" dependencies = [ "num-bigint", "num-traits", - "thiserror", + "thiserror 2.0.18", "time", ] +[[package]] +name = "siphasher" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e" + +[[package]] +name = "sketches-ddsketch" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1e9a774a6c28142ac54bb25d25562e6bcf957493a184f15ad4eebccb23e410a" + [[package]] name = "slab" version = "0.4.12" @@ -4230,6 +7778,22 @@ dependencies = [ "serde", ] +[[package]] +name = "snap" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b6b67fb9a61334225b5b790716f609cd58395f895b3fe8b328786812a40bc3b" + +[[package]] +name = "socket2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + [[package]] name = "socket2" version = "0.6.2" @@ -4240,6 +7804,22 @@ dependencies = [ "windows-sys 0.60.2", ] +[[package]] +name = "soketto" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e859df029d160cb88608f5d7df7fb4753fd20fdfb4de5644f3d8b8440841721" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures", + "http 1.4.0", + "httparse", + "log", + "rand 0.8.5", + "sha1", +] + [[package]] name = "spki" version = "0.7.3" @@ -4268,6 +7848,29 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[package]] +name = "structmeta" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e1575d8d40908d70f6fd05537266b90ae71b15dbbe7a8b7dffa2b759306d329" +dependencies = [ + "proc-macro2", + "quote", + "structmeta-derive", + "syn 2.0.115", +] + +[[package]] +name = "structmeta-derive" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "152a0b65a590ff6c3da95cabe2353ee04e6167c896b28e3b14478c2636c922fc" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", +] + [[package]] name = "strum" version = "0.26.3" @@ -4296,7 +7899,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.114", + "syn 2.0.115", ] [[package]] @@ -4308,7 +7911,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.115", ] [[package]] @@ -4330,9 +7933,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.114" +version = "2.0.115" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" +checksum = "6e614ed320ac28113fa64972c4262d5dbc89deacdfd00c34a3e4cea073243c12" dependencies = [ "proc-macro2", "quote", @@ -4341,14 +7944,14 @@ dependencies = [ [[package]] name = "syn-solidity" -version = "1.5.4" +version = "1.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2379beea9476b89d0237078be761cf8e012d92d5ae4ae0c9a329f974838870fc" +checksum = "f8658017776544996edc21c8c7cc8bb4f13db60955382f4bac25dc6303b38438" dependencies = [ "paste", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.115", ] [[package]] @@ -4368,9 +7971,15 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.115", ] +[[package]] +name = "tagptr" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b2093cf4c8eb1e67749a6762251bc9cd836b6fc171623bd0a9d324d37af2417" + [[package]] name = "tap" version = "1.0.1" @@ -4379,24 +7988,88 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" -version = "3.24.0" +version = "3.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "655da9c7eb6305c55742045d5a8d2037996d61d8de95806335c7c86ce0f82e9c" +checksum = "0136791f7c95b1f6dd99f9cc786b91bb81c3800b639b3478e561ddb7be95e5f1" dependencies = [ "fastrand", - "getrandom 0.3.4", + "getrandom 0.4.1", "once_cell", "rustix 1.1.3", "windows-sys 0.61.2", ] +[[package]] +name = "termtree" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f50febec83f5ee1df3015341d8bd429f2d1cc62bcba7ea2076759d315084683" + +[[package]] +name = "testcontainers" +version = "0.23.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59a4f01f39bb10fc2a5ab23eb0d888b1e2bb168c157f61a1b98e6c501c639c74" +dependencies = [ + "async-trait", + "bollard", + "bollard-stubs", + "bytes", + "docker_credential", + "either", + "etcetera", + "futures", + "log", + "memchr", + "parse-display", + "pin-project-lite", + "serde", + "serde_json", + "serde_with", + "thiserror 2.0.18", + "tokio", + "tokio-stream", + "tokio-tar", + "tokio-util", + "url", +] + +[[package]] +name = "testcontainers-modules" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d43ed4e8f58424c3a2c6c56dbea6643c3c23e8666a34df13c54f0a184e6c707" +dependencies = [ + "testcontainers", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + [[package]] name = "thiserror" version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" dependencies = [ - "thiserror-impl", + "thiserror-impl 2.0.18", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", ] [[package]] @@ -4407,7 +8080,7 @@ checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.115", ] [[package]] @@ -4483,6 +8156,21 @@ dependencies = [ "zerovec", ] +[[package]] +name = "tinyvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" +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.49.0" @@ -4495,7 +8183,7 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2", + "socket2 0.6.2", "tokio-macros", "windows-sys 0.61.2", ] @@ -4508,7 +8196,7 @@ checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.115", ] [[package]] @@ -4521,13 +8209,23 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-rustls" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +dependencies = [ + "rustls 0.21.12", + "tokio", +] + [[package]] name = "tokio-rustls" version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" dependencies = [ - "rustls", + "rustls 0.23.36", "tokio", ] @@ -4543,6 +8241,21 @@ dependencies = [ "tokio-util", ] +[[package]] +name = "tokio-tar" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d5714c010ca3e5c27114c1cdeb9d14641ace49874aa5626d7149e47aedace75" +dependencies = [ + "filetime", + "futures-core", + "libc", + "redox_syscall 0.3.5", + "tokio", + "tokio-stream", + "xattr", +] + [[package]] name = "tokio-tungstenite" version = "0.26.2" @@ -4552,11 +8265,11 @@ dependencies = [ "futures-util", "log", "native-tls", - "rustls", + "rustls 0.23.36", "rustls-pki-types", "tokio", "tokio-native-tls", - "tokio-rustls", + "tokio-rustls 0.26.4", "tungstenite", "webpki-roots 0.26.11", ] @@ -4569,6 +8282,7 @@ checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" dependencies = [ "bytes", "futures-core", + "futures-io", "futures-sink", "pin-project-lite", "tokio", @@ -4597,9 +8311,9 @@ dependencies = [ [[package]] name = "toml_parser" -version = "1.0.6+spec-1.1.0" +version = "1.0.7+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3198b4b0a8e11f09dd03e133c0280504d0801269e9afa46362ffde1cbeebf44" +checksum = "247eaa3197818b831697600aadf81514e577e0cba5eab10f7e064e78ae154df1" dependencies = [ "winnow", ] @@ -4625,11 +8339,11 @@ version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" dependencies = [ - "bitflags", + "bitflags 2.10.0", "bytes", "futures-util", - "http", - "http-body", + "http 1.4.0", + "http-body 1.0.1", "iri-string", "pin-project-lite", "tower", @@ -4668,7 +8382,7 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.115", ] [[package]] @@ -4681,6 +8395,16 @@ dependencies = [ "valuable", ] +[[package]] +name = "tracing-futures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" +dependencies = [ + "pin-project", + "tracing", +] + [[package]] name = "tracing-log" version = "0.2.0" @@ -4704,7 +8428,7 @@ dependencies = [ "tracing", "tracing-core", "tracing-log", - "tracing-subscriber", + "tracing-subscriber 0.3.22", "web-time", ] @@ -4718,6 +8442,15 @@ dependencies = [ "tracing-core", ] +[[package]] +name = "tracing-subscriber" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71" +dependencies = [ + "tracing-core", +] + [[package]] name = "tracing-subscriber" version = "0.3.22" @@ -4751,15 +8484,15 @@ checksum = "4793cb5e56680ecbb1d843515b23b6de9a75eb04b66643e256a396d43be33c13" dependencies = [ "bytes", "data-encoding", - "http", + "http 1.4.0", "httparse", "log", "native-tls", "rand 0.9.2", - "rustls", + "rustls 0.23.36", "rustls-pki-types", "sha1", - "thiserror", + "thiserror 2.0.18", "utf-8", ] @@ -4795,9 +8528,9 @@ checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" [[package]] name = "unicode-ident" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" +checksum = "537dd038a89878be9b64dd4bd1b260315c1bb94f4d784956b81e27a088d9a09e" [[package]] name = "unicode-segmentation" @@ -4859,6 +8592,12 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "urlencoding" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" + [[package]] name = "utf-8" version = "0.7.6" @@ -4877,6 +8616,30 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" +[[package]] +name = "utils" +version = "0.0.0" +dependencies = [ + "alloy-rpc-types", + "metrics-exporter-prometheus", + "serde_json", + "tracing", + "tracing-subscriber 0.3.22", +] + +[[package]] +name = "uuid" +version = "1.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee48d38b119b0cd71fe4141b30f5ba9c7c5d9f4e7a3a8b4a674e4b6ef789976f" +dependencies = [ + "getrandom 0.3.4", + "js-sys", + "serde_core", + "sha1_smol", + "wasm-bindgen", +] + [[package]] name = "valuable" version = "0.1.1" @@ -4895,6 +8658,12 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "vsimd" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c3082ca00d5a5ef149bb8b555a72ae84c9c59f7250f013ac822ac2e49b19c64" + [[package]] name = "wait-timeout" version = "0.2.1" @@ -4904,6 +8673,16 @@ dependencies = [ "libc", ] +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "want" version = "0.3.1" @@ -4928,6 +8707,15 @@ dependencies = [ "wit-bindgen", ] +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen", +] + [[package]] name = "wasm-bindgen" version = "0.2.108" @@ -4974,7 +8762,7 @@ dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.115", "wasm-bindgen-shared", ] @@ -4987,6 +8775,40 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap 2.13.0", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags 2.10.0", + "hashbrown 0.15.5", + "indexmap 2.13.0", + "semver 1.0.27", +] + [[package]] name = "wasmtimer" version = "0.4.3" @@ -5021,6 +8843,24 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webpki-root-certs" +version = "0.26.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75c7f0ef91146ebfb530314f5f1d24528d7f0767efbfd31dce919275413e393e" +dependencies = [ + "webpki-root-certs 1.0.6", +] + +[[package]] +name = "webpki-root-certs" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "804f18a4ac2676ffb4e8b5b5fa9ae38af06df08162314f96a68d2a363e21a8ca" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "webpki-roots" version = "0.26.11" @@ -5061,6 +8901,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.61.2", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" @@ -5088,7 +8937,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.115", ] [[package]] @@ -5099,7 +8948,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.115", ] [[package]] @@ -5126,6 +8975,24 @@ dependencies = [ "windows-link", ] +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[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" @@ -5162,6 +9029,36 @@ dependencies = [ "windows-link", ] +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[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.6" @@ -5195,6 +9092,18 @@ dependencies = [ "windows_x86_64_msvc 0.53.1", ] +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[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.6" @@ -5207,6 +9116,18 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[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.6" @@ -5219,6 +9140,18 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[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.6" @@ -5243,6 +9176,18 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[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.6" @@ -5255,6 +9200,18 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[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.6" @@ -5267,6 +9224,18 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[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.6" @@ -5279,6 +9248,18 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[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.6" @@ -5300,11 +9281,116 @@ dependencies = [ "memchr", ] +[[package]] +name = "wiremock" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08db1edfb05d9b3c1542e521aea074442088292f00b5f28e435c714a98f85031" +dependencies = [ + "assert-json-diff", + "base64 0.22.1", + "deadpool", + "futures", + "http 1.4.0", + "http-body-util", + "hyper 1.8.1", + "hyper-util", + "log", + "once_cell", + "regex", + "serde", + "serde_json", + "tokio", + "url", +] + [[package]] name = "wit-bindgen" version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck", + "indexmap 2.13.0", + "prettyplease", + "syn 2.0.115", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn 2.0.115", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags 2.10.0", + "indexmap 2.13.0", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap 2.13.0", + "log", + "semver 1.0.27", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] [[package]] name = "writeable" @@ -5325,7 +9411,7 @@ dependencies = [ "pharos", "rustc_version 0.4.1", "send_wrapper", - "thiserror", + "thiserror 2.0.18", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", @@ -5357,6 +9443,22 @@ version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea6fc2961e4ef194dcbfe56bb845534d0dc8098940c7e5c012a258bfec6701bd" +[[package]] +name = "xattr" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156" +dependencies = [ + "libc", + "rustix 1.1.3", +] + +[[package]] +name = "xmlparser" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66fee0b777b0f5ac1c69bb06d361268faafa61cd4682ae064a171c16c433e9e4" + [[package]] name = "yoke" version = "0.8.1" @@ -5376,7 +9478,7 @@ checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.115", "synstructure", ] @@ -5397,7 +9499,7 @@ checksum = "4122cd3169e94605190e77839c9a40d40ed048d305bfdc146e7df40ab0f3e517" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.115", ] [[package]] @@ -5417,7 +9519,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.115", "synstructure", ] @@ -5438,7 +9540,7 @@ checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.115", ] [[package]] @@ -5471,14 +9573,43 @@ checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.114", + "syn 2.0.115", ] [[package]] name = "zmij" -version = "1.0.19" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" + +[[package]] +name = "zstd" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.16+zstd.1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ff05f8caa9038894637571ae6b9e29466c1f4f829d26c9b28f869a29cbe3445" +checksum = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748" +dependencies = [ + "bindgen", + "cc", + "pkg-config", +] [[package]] name = "zune-core" diff --git a/Cargo.toml b/Cargo.toml index c102d3e..42c5ccd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,13 +1,19 @@ -[workspace] -resolver = "2" -members = ["crates/*", "bin/*"] -default-members = ["bin/*"] -exclude = [".github/"] + [workspace.package] version = "0.0.0" edition = "2024" +rust-version = "1.88" license = "MIT" +homepage = "https://github.com/base/infra" +repository = "https://github.com/base/infra" +exclude = [".github/"] + +[workspace] +resolver = "2" +members = ["crates/*", "bin/*"] +default-members = ["bin/*"] +exclude = [".github/"] [workspace.lints.rust] missing-debug-implementations = "warn" @@ -44,42 +50,37 @@ needless-pass-by-ref-mut = "warn" string-lit-as-bytes = "warn" [workspace.dependencies] -cadence = "1.4" -clap = { version = "4.0", features = ["derive", "env"] } -tokio-tungstenite = { version = "0.26", features = ["native-tls"] } -futures-util = "0.3" -url = "2.5" -ratatui = "0.29" -crossterm = "0.28" -chrono = "0.4" -anyhow = "1.0" -serde_yaml = "0.9" -dirs = "6.0" -arboard = "3.4" -dotenvy = "0.15.7" -async-trait = "0.1" -mempool-rebroadcaster = { path = "./crates/mempool-rebroadcaster" } -sidecrush = { path = "./crates/sidecrush" } -metrics = "0.24.1" -metrics-derive = "0.1" -tracing = "0.1" -tracing-subscriber = { version = "0.3", default-features = false, features = ["env-filter", "fmt", "ansi", "json"] } -tokio = { version = "1.0", features = ["full"] } -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" +# Internal crates +audit = { path = "crates/audit" } +basectl-cli = { path = "crates/basectl" } +mempool-rebroadcaster = { path = "crates/mempool-rebroadcaster" } +sidecrush = { path = "crates/sidecrush" } +utils = { path = "crates/utils" } +ingress-rpc = { path = "crates/ingress-rpc" } + +# base-reth +base-bundles = { git = "https://github.com/base/base", branch = "main" } +base-primitives = { git = "https://github.com/base/base.git", features = ["flashblocks"] } +base-reth-rpc-types = { git = "https://github.com/base/base", branch = "main" } + +# revm +op-revm = { version = "15.0.0", default-features = false } +revm-context-interface = { version = "15.0.0", default-features = false } # alloy -alloy-primitives = { version = "1.5.2", default-features = false, features = [ - "map-foldhash", -] } -alloy-genesis = { version = "1.5.2", default-features = false } -alloy-eips = { version = "1.5.2", default-features = false } -alloy-rpc-types = { version = "1.5.2", default-features = false } -alloy-rpc-types-engine = { version = "1.5.2", default-features = false } -alloy-rpc-types-eth = { version = "1.5.2" } -alloy-consensus = { version = "1.5.2" } -alloy-trie = { version = "0.9.1", default-features = false } +alloy-serde = { version = "1.0.41", default-features = false } +alloy-signer = { version = "1.0.41", default-features = false } +alloy-network = { version = "1.0.41", default-features = false } alloy-provider = { version = "1.5.2", features = ["ws", "pubsub"] } +alloy-consensus = { version = "1.0.41", default-features = false } +alloy-rpc-types = { version = "1.1.2", default-features = false } +alloy-primitives = { version = "1.4.1", default-features = false } +alloy-signer-local = { version = "1.0.41", default-features = false } +alloy-genesis = { version = "1.0.41", default-features = false } +alloy-eips = { version = "1.0.41", default-features = false } +alloy-rpc-types-engine = { version = "1.0.41", default-features = false } +alloy-rpc-types-eth = { version = "1.0.41" } +alloy-trie = { version = "0.9.1", default-features = false } alloy-hardforks = { version = "0.5" } alloy-rpc-client = { version = "1.5.2" } alloy-transport-http = { version = "1.5.2" } @@ -87,11 +88,54 @@ alloy-sol-types = { version = "1.5.2" } alloy-contract = { version = "1.5.2" } # op-alloy +op-alloy-flz = { version = "0.13.1", default-features = false } op-alloy-network = { version = "0.22.0", default-features = false } op-alloy-rpc-types = { version = "0.22.0", default-features = false } -op-alloy-rpc-types-engine = { version = "0.22.0", default-features = false } op-alloy-consensus = { version = "0.22.0", default-features = false } +op-alloy-rpc-types-engine = { version = "0.22.0", default-features = false } -# base -base-flashtypes = { git = "https://github.com/base/base.git" } -basectl-cli = { path = "crates/basectl" } +# tokio +tokio = { version = "1.47.1", features = ["full"] } + +# async +async-trait = "0.1.89" +futures = { version = "0.3.31", default-features = false } +futures-util = "0.3" + +# rpc +jsonrpsee = { version = "0.26.0", default-features = false } + +# kafka and s3 +bytes = { version = "1.8.0", default-features = false } +rdkafka = { version = "0.37.0", default-features = false } +aws-config = { version = "1.1.7", default-features = false } +aws-sdk-s3 = { version = "1.106.0", default-features = false } +aws-credential-types = { version = "1.1.7", default-features = false } + +# misc +tokio-tungstenite = { version = "0.26", features = ["native-tls"] } +url = { version = "2.5.7", default-features = false } +axum = { version = "0.8.3", default-features = false } +ratatui = "0.29" +crossterm = "0.28" +clap = { version = "4.5.47", default-features = false, features = ["std", "derive", "env"] } +chrono = "0.4" +anyhow = { version = "1.0.99", default-features = false } +serde = { version = "1.0.219", default-features = false, features = ["derive"] } +serde_json = { version = "1.0.143", default-features = false } +serde_yaml = "0.9" +uuid = { version = "1.18.1", default-features = false } +backon = { version = "1.5.2", default-features = false } +dirs = "6.0" +arboard = "3.4" +dotenvy = { version = "0.15.7", default-features = false } +tracing = { version = "0.1.41", default-features = false } +tracing-subscriber = { version = "0.3.20", default-features = false, features = ["env-filter", "fmt", "ansi", "json"] } +wiremock = { version = "0.6.2", default-features = false } +metrics = { version = "0.24.1", default-features = false } +metrics-derive = { version = "0.1", default-features = false } +metrics-exporter-prometheus = { version = "0.17.0", default-features = false } +testcontainers = { version = "0.23.1", default-features = false } +testcontainers-modules = { version = "0.11.2", default-features = false } +moka = { version = "0.12.12", default-features = false } +cadence = "1.4" diff --git a/bin/audit/Cargo.toml b/bin/audit/Cargo.toml new file mode 100644 index 0000000..cf87213 --- /dev/null +++ b/bin/audit/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "audit-bin" +version.workspace = true +rust-version.workspace = true +license.workspace = true +homepage.workspace = true +repository.workspace = true +edition.workspace = true + +[lints] +workspace = true + +[[bin]] +name = "audit" +path = "src/main.rs" + +[dependencies] +utils.workspace = true +audit.workspace = true +clap.workspace = true +tokio.workspace = true +anyhow.workspace = true +tracing.workspace = true +dotenvy.workspace = true +rdkafka.workspace = true +aws-config.workspace = true +aws-sdk-s3.workspace = true +aws-credential-types.workspace = true diff --git a/bin/audit/src/main.rs b/bin/audit/src/main.rs new file mode 100644 index 0000000..0e6dac4 --- /dev/null +++ b/bin/audit/src/main.rs @@ -0,0 +1,135 @@ +use std::net::SocketAddr; + +use anyhow::Result; +use audit::{KafkaAuditArchiver, KafkaAuditLogReader, S3EventReaderWriter, create_kafka_consumer}; +use aws_config::{BehaviorVersion, Region}; +use aws_credential_types::Credentials; +use aws_sdk_s3::{Client as S3Client, config::Builder as S3ConfigBuilder}; +use clap::{Parser, ValueEnum}; +use rdkafka::consumer::Consumer; +use tracing::info; +use utils::{logger::init_logger_with_format, metrics::init_prometheus_exporter}; + +#[derive(Debug, Clone, ValueEnum)] +enum S3ConfigType { + Aws, + Manual, +} + +#[derive(Parser, Debug)] +#[command(author, version, about, long_about = None)] +struct Args { + #[arg(long, env = "TIPS_AUDIT_KAFKA_PROPERTIES_FILE")] + kafka_properties_file: String, + + #[arg(long, env = "TIPS_AUDIT_KAFKA_TOPIC")] + kafka_topic: String, + + #[arg(long, env = "TIPS_AUDIT_S3_BUCKET")] + s3_bucket: String, + + #[arg(long, env = "TIPS_AUDIT_LOG_LEVEL", default_value = "info")] + log_level: String, + + #[arg(long, env = "TIPS_AUDIT_LOG_FORMAT", default_value = "pretty")] + log_format: utils::logger::LogFormat, + + #[arg(long, env = "TIPS_AUDIT_S3_CONFIG_TYPE", default_value = "aws")] + s3_config_type: S3ConfigType, + + #[arg(long, env = "TIPS_AUDIT_S3_ENDPOINT")] + s3_endpoint: Option, + + #[arg(long, env = "TIPS_AUDIT_S3_REGION", default_value = "us-east-1")] + s3_region: String, + + #[arg(long, env = "TIPS_AUDIT_S3_ACCESS_KEY_ID")] + s3_access_key_id: Option, + + #[arg(long, env = "TIPS_AUDIT_S3_SECRET_ACCESS_KEY")] + s3_secret_access_key: Option, + + #[arg(long, env = "TIPS_AUDIT_METRICS_ADDR", default_value = "0.0.0.0:9002")] + metrics_addr: SocketAddr, + + #[arg(long, env = "TIPS_AUDIT_WORKER_POOL_SIZE", default_value = "80")] + worker_pool_size: usize, + + #[arg(long, env = "TIPS_AUDIT_CHANNEL_BUFFER_SIZE", default_value = "500")] + channel_buffer_size: usize, + + #[arg(long, env = "TIPS_AUDIT_NOOP_ARCHIVE", default_value = "false")] + noop_archive: bool, +} + +#[tokio::main] +async fn main() -> Result<()> { + dotenvy::dotenv().ok(); + + let args = Args::parse(); + + init_logger_with_format(&args.log_level, args.log_format); + + init_prometheus_exporter(args.metrics_addr).expect("Failed to install Prometheus exporter"); + + info!( + kafka_properties_file = %args.kafka_properties_file, + kafka_topic = %args.kafka_topic, + s3_bucket = %args.s3_bucket, + metrics_addr = %args.metrics_addr, + "Starting audit archiver" + ); + + let consumer = create_kafka_consumer(&args.kafka_properties_file)?; + consumer.subscribe(&[&args.kafka_topic])?; + + let reader = KafkaAuditLogReader::new(consumer, args.kafka_topic.clone())?; + + let s3_client = create_s3_client(&args).await?; + let s3_bucket = args.s3_bucket.clone(); + let writer = S3EventReaderWriter::new(s3_client, s3_bucket); + + let mut archiver = KafkaAuditArchiver::new( + reader, + writer, + args.worker_pool_size, + args.channel_buffer_size, + args.noop_archive, + ); + + info!("Audit archiver initialized, starting main loop"); + + archiver.run().await +} + +async fn create_s3_client(args: &Args) -> Result { + match args.s3_config_type { + S3ConfigType::Manual => { + let region = args.s3_region.clone(); + let mut config_builder = + aws_config::defaults(BehaviorVersion::latest()).region(Region::new(region)); + + if let Some(endpoint) = &args.s3_endpoint { + config_builder = config_builder.endpoint_url(endpoint); + } + + if let (Some(access_key), Some(secret_key)) = + (&args.s3_access_key_id, &args.s3_secret_access_key) + { + let credentials = Credentials::new(access_key, secret_key, None, None, "manual"); + config_builder = config_builder.credentials_provider(credentials); + } + + let config = config_builder.load().await; + let s3_config_builder = S3ConfigBuilder::from(&config).force_path_style(true); + + info!(message = "manually configuring s3 client"); + Ok(S3Client::from_conf(s3_config_builder.build())) + } + S3ConfigType::Aws => { + info!(message = "using aws s3 client"); + let config = aws_config::load_defaults(BehaviorVersion::latest()).await; + Ok(S3Client::new(&config)) + } + } +} diff --git a/bin/ingress-rpc/Cargo.toml b/bin/ingress-rpc/Cargo.toml new file mode 100644 index 0000000..e7155c3 --- /dev/null +++ b/bin/ingress-rpc/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "ingress-rpc-bin" +version.workspace = true +rust-version.workspace = true +license.workspace = true +homepage.workspace = true +repository.workspace = true +edition.workspace = true + +[lints] +workspace = true + +[[bin]] +name = "ingress-rpc" +path = "src/main.rs" + + +[dependencies] +utils.workspace = true +base-bundles.workspace = true +audit.workspace = true +ingress-rpc.workspace = true +clap.workspace = true +tokio.workspace = true +anyhow.workspace = true +tracing.workspace = true +dotenvy.workspace = true +rdkafka.workspace = true +jsonrpsee.workspace = true +op-alloy-network.workspace = true +alloy-provider.workspace = true diff --git a/bin/ingress-rpc/src/main.rs b/bin/ingress-rpc/src/main.rs new file mode 100644 index 0000000..85a52fe --- /dev/null +++ b/bin/ingress-rpc/src/main.rs @@ -0,0 +1,109 @@ +use alloy_provider::ProviderBuilder; +use audit::{BundleEvent, KafkaBundleEventPublisher, connect_audit_to_publisher}; +use base_bundles::{AcceptedBundle, MeterBundleResponse}; +use clap::Parser; +use ingress_rpc::{ + Config, connect_ingress_to_builder, + health::bind_health_server, + queue::KafkaMessageQueue, + service::{IngressApiServer, IngressService, Providers}, +}; +use jsonrpsee::server::Server; +use op_alloy_network::Optimism; +use rdkafka::{ClientConfig, producer::FutureProducer}; +use tokio::sync::{broadcast, mpsc}; +use tracing::info; +use utils::{ + kafka::load_kafka_config_from_file, logger::init_logger_with_format, + metrics::init_prometheus_exporter, +}; + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + dotenvy::dotenv().ok(); + + let config = Config::parse(); + let cfg = config.clone(); + + init_logger_with_format(&config.log_level, config.log_format); + + init_prometheus_exporter(config.metrics_addr).expect("Failed to install Prometheus exporter"); + + info!( + message = "Starting ingress service", + address = %config.address, + port = config.port, + mempool_url = %config.mempool_url, + simulation_rpc = %config.simulation_rpc, + metrics_address = %config.metrics_addr, + health_check_address = %config.health_check_addr, + ); + + let providers = Providers { + mempool: ProviderBuilder::new() + .disable_recommended_fillers() + .network::() + .connect_http(config.mempool_url), + simulation: ProviderBuilder::new() + .disable_recommended_fillers() + .network::() + .connect_http(config.simulation_rpc), + raw_tx_forward: config.raw_tx_forward_rpc.clone().map(|url| { + ProviderBuilder::new() + .disable_recommended_fillers() + .network::() + .connect_http(url) + }), + }; + + let ingress_client_config = + ClientConfig::from_iter(load_kafka_config_from_file(&config.ingress_kafka_properties)?); + + let queue_producer: FutureProducer = ingress_client_config.create()?; + + let queue = KafkaMessageQueue::new(queue_producer); + + let audit_client_config = + ClientConfig::from_iter(load_kafka_config_from_file(&config.audit_kafka_properties)?); + + let audit_producer: FutureProducer = audit_client_config.create()?; + + let audit_publisher = KafkaBundleEventPublisher::new(audit_producer, config.audit_topic); + let (audit_tx, audit_rx) = mpsc::unbounded_channel::(); + connect_audit_to_publisher(audit_rx, audit_publisher); + + let (builder_tx, _) = + broadcast::channel::(config.max_buffered_meter_bundle_responses); + let (builder_backrun_tx, _) = + broadcast::channel::(config.max_buffered_backrun_bundles); + config.builder_rpcs.iter().for_each(|builder_rpc| { + let metering_rx = builder_tx.subscribe(); + let backrun_rx = builder_backrun_tx.subscribe(); + connect_ingress_to_builder(metering_rx, backrun_rx, builder_rpc.clone()); + }); + + let health_check_addr = config.health_check_addr; + let (bound_health_addr, health_handle) = bind_health_server(health_check_addr).await?; + info!( + message = "Health check server started", + address = %bound_health_addr + ); + + let service = + IngressService::new(providers, queue, audit_tx, builder_tx, builder_backrun_tx, cfg); + let bind_addr = format!("{}:{}", config.address, config.port); + + let server = Server::builder().build(&bind_addr).await?; + let addr = server.local_addr()?; + let handle = server.start(service.into_rpc()); + + info!( + message = "Ingress RPC server started", + address = %addr + ); + + handle.stopped().await; + health_handle.abort(); + + Ok(()) +} diff --git a/crates/audit/Cargo.toml b/crates/audit/Cargo.toml new file mode 100644 index 0000000..08c96d3 --- /dev/null +++ b/crates/audit/Cargo.toml @@ -0,0 +1,40 @@ +[package] +name = "audit" +version.workspace = true +rust-version.workspace = true +license.workspace = true +homepage.workspace = true +repository.workspace = true +edition.workspace = true + +[lints] +workspace = true + +[dependencies] +bytes.workspace = true +metrics.workspace = true +async-trait.workspace = true +metrics-derive.workspace = true +base-bundles.workspace = true +utils = { workspace = true } +serde = { workspace = true, features = ["std", "derive"] } +tokio = { workspace = true, features = ["full"] } +uuid = { workspace = true, features = ["v5", "serde"] } +tracing = { workspace = true, features = ["std"] } +anyhow = { workspace = true, features = ["std"] } +serde_json = { workspace = true, features = ["std"] } +rdkafka = { workspace = true, features = ["tokio", "libz", "zstd", "ssl-vendored"] } +alloy-consensus = { workspace = true, features = ["std"] } +alloy-provider = { workspace = true } +alloy-primitives = { workspace = true, features = ["map-foldhash", "serde"] } +aws-sdk-s3 = { workspace = true, features = ["rustls", "default-https-client", "rt-tokio"] } +futures = { workspace = true } +alloy-signer-local = { workspace = true } +op-alloy-consensus = { workspace = true } +op-alloy-rpc-types = { workspace = true } + +[dev-dependencies] +audit = { workspace = true } +testcontainers = { workspace = true, features = ["blocking"] } +testcontainers-modules = { workspace = true, features = ["postgres", "kafka", "minio"] } +aws-config = { workspace = true, features = ["default-https-client", "rt-tokio"] } diff --git a/crates/audit/src/archiver.rs b/crates/audit/src/archiver.rs new file mode 100644 index 0000000..d622094 --- /dev/null +++ b/crates/audit/src/archiver.rs @@ -0,0 +1,156 @@ +use std::{ + fmt, + marker::PhantomData, + sync::Arc, + time::{Duration, Instant, SystemTime, UNIX_EPOCH}, +}; + +use anyhow::Result; +use tokio::{ + sync::{Mutex, mpsc}, + time::sleep, +}; +use tracing::{error, info}; + +use crate::{ + metrics::Metrics, + reader::{Event, EventReader}, + storage::EventWriter, +}; + +/// Archives audit events from Kafka to S3 storage. +pub struct KafkaAuditArchiver +where + R: EventReader, + W: EventWriter + Clone + Send + 'static, +{ + reader: R, + event_tx: mpsc::Sender, + metrics: Metrics, + _phantom: PhantomData, +} + +impl fmt::Debug for KafkaAuditArchiver +where + R: EventReader, + W: EventWriter + Clone + Send + 'static, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("KafkaAuditArchiver").finish_non_exhaustive() + } +} + +impl KafkaAuditArchiver +where + R: EventReader, + W: EventWriter + Clone + Send + 'static, +{ + /// Creates a new archiver with the given reader and writer. + pub fn new( + reader: R, + writer: W, + worker_pool_size: usize, + channel_buffer_size: usize, + noop_archive: bool, + ) -> Self { + let (event_tx, event_rx) = mpsc::channel(channel_buffer_size); + let metrics = Metrics::default(); + + Self::spawn_workers(writer, event_rx, metrics.clone(), worker_pool_size, noop_archive); + + Self { reader, event_tx, metrics, _phantom: PhantomData } + } + + fn spawn_workers( + writer: W, + event_rx: mpsc::Receiver, + metrics: Metrics, + worker_pool_size: usize, + noop_archive: bool, + ) { + let event_rx = Arc::new(Mutex::new(event_rx)); + + for worker_id in 0..worker_pool_size { + let writer = writer.clone(); + let metrics = metrics.clone(); + let event_rx = Arc::clone(&event_rx); + + tokio::spawn(async move { + loop { + let event = { + let mut rx = event_rx.lock().await; + rx.recv().await + }; + + match event { + Some(event) => { + let archive_start = Instant::now(); + // tmp: only use this to clear kafka consumer offset + // TODO: use debug! later + if noop_archive { + info!( + worker_id, + bundle_id = %event.event.bundle_id(), + tx_ids = ?event.event.transaction_ids(), + timestamp = event.timestamp, + "Noop archive - skipping event" + ); + metrics.events_processed.increment(1); + metrics.in_flight_archive_tasks.decrement(1.0); + continue; + } + if let Err(e) = writer.archive_event(event).await { + error!(worker_id, error = %e, "Failed to write event"); + } else { + metrics + .archive_event_duration + .record(archive_start.elapsed().as_secs_f64()); + metrics.events_processed.increment(1); + } + metrics.in_flight_archive_tasks.decrement(1.0); + } + None => { + info!(worker_id, "Worker stopped - channel closed"); + break; + } + } + } + }); + } + } + + /// Runs the archiver loop, reading events and writing them to storage. + pub async fn run(&mut self) -> Result<()> { + loop { + let read_start = Instant::now(); + match self.reader.read_event().await { + Ok(event) => { + self.metrics.kafka_read_duration.record(read_start.elapsed().as_secs_f64()); + + let now_ms = SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap_or_default() + .as_millis() as i64; + let event_age_ms = now_ms.saturating_sub(event.timestamp); + self.metrics.event_age.record(event_age_ms as f64); + + self.metrics.in_flight_archive_tasks.increment(1.0); + if let Err(e) = self.event_tx.send(event).await { + error!(error = %e, "Failed to send event to worker pool"); + self.metrics.in_flight_archive_tasks.decrement(1.0); + } + + let commit_start = Instant::now(); + if let Err(e) = self.reader.commit().await { + error!(error = %e, "Failed to commit message"); + } + self.metrics.kafka_commit_duration.record(commit_start.elapsed().as_secs_f64()); + } + Err(e) => { + error!(error = %e, "Error reading events"); + sleep(Duration::from_secs(1)).await; + } + } + } + } +} diff --git a/crates/audit/src/lib.rs b/crates/audit/src/lib.rs new file mode 100644 index 0000000..060ded8 --- /dev/null +++ b/crates/audit/src/lib.rs @@ -0,0 +1,76 @@ +//! Audit library for tracking and archiving bundle and user operation events. +//! +//! This crate provides functionality for publishing events to Kafka, +//! archiving them to S3, and reading event history. + +#![doc(issue_tracker_base_url = "https://github.com/base/tips/issues/")] +#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] +#![cfg_attr(not(test), warn(unused_crate_dependencies))] + +mod archiver; +pub use archiver::KafkaAuditArchiver; + +mod metrics; +pub use metrics::Metrics; + +mod publisher; +pub use publisher::{ + BundleEventPublisher, KafkaBundleEventPublisher, KafkaUserOpEventPublisher, + LoggingBundleEventPublisher, LoggingUserOpEventPublisher, UserOpEventPublisher, +}; + +mod reader; +pub use reader::{ + Event, EventReader, KafkaAuditLogReader, KafkaUserOpAuditLogReader, UserOpEventReader, + UserOpEventWrapper, assign_topic_partition, create_kafka_consumer, +}; + +mod storage; +pub use storage::{ + BundleEventS3Reader, BundleHistory, BundleHistoryEvent, EventWriter, S3EventReaderWriter, + S3Key, TransactionMetadata, UserOpEventS3Reader, UserOpEventWriter, UserOpHistory, + UserOpHistoryEvent, +}; + +pub mod test_utils; + +use tokio::sync::mpsc; +use tracing::error; + +mod types; +pub use types::{ + BundleEvent, BundleId, DropReason, Transaction, TransactionId, UserOpDropReason, UserOpEvent, + UserOpHash, +}; + +/// Connects a bundle event receiver to a publisher, spawning a task to forward events. +pub fn connect_audit_to_publisher

(event_rx: mpsc::UnboundedReceiver, publisher: P) +where + P: BundleEventPublisher + 'static, +{ + tokio::spawn(async move { + let mut event_rx = event_rx; + while let Some(event) = event_rx.recv().await { + if let Err(e) = publisher.publish(event).await { + error!(error = %e, "failed to publish bundle event"); + } + } + }); +} + +/// Connects a user operation event receiver to a publisher, spawning a task to forward events. +pub fn connect_userop_audit_to_publisher

( + event_rx: mpsc::UnboundedReceiver, + publisher: P, +) where + P: UserOpEventPublisher + 'static, +{ + tokio::spawn(async move { + let mut event_rx = event_rx; + while let Some(event) = event_rx.recv().await { + if let Err(e) = publisher.publish(event).await { + error!(error = %e, "Failed to publish user op event"); + } + } + }); +} diff --git a/crates/audit/src/metrics.rs b/crates/audit/src/metrics.rs new file mode 100644 index 0000000..257b879 --- /dev/null +++ b/crates/audit/src/metrics.rs @@ -0,0 +1,55 @@ +use metrics::{Counter, Gauge, Histogram}; +use metrics_derive::Metrics; + +/// Metrics for audit operations including Kafka reads, S3 writes, and event processing. +#[derive(Metrics, Clone)] +#[metrics(scope = "tips_audit")] +pub struct Metrics { + /// Duration of `archive_event` operations. + #[metric(describe = "Duration of archive_event")] + pub archive_event_duration: Histogram, + + /// Age of event when processed (now - event timestamp). + #[metric(describe = "Age of event when processed (now - event timestamp)")] + pub event_age: Histogram, + + /// Duration of Kafka `read_event` operations. + #[metric(describe = "Duration of Kafka read_event")] + pub kafka_read_duration: Histogram, + + /// Duration of Kafka commit operations. + #[metric(describe = "Duration of Kafka commit")] + pub kafka_commit_duration: Histogram, + + /// Duration of `update_bundle_history` operations. + #[metric(describe = "Duration of update_bundle_history")] + pub update_bundle_history_duration: Histogram, + + /// Duration of updating all transaction indexes. + #[metric(describe = "Duration of update all transaction indexes")] + pub update_tx_indexes_duration: Histogram, + + /// Duration of S3 `get_object` operations. + #[metric(describe = "Duration of S3 get_object")] + pub s3_get_duration: Histogram, + + /// Duration of S3 `put_object` operations. + #[metric(describe = "Duration of S3 put_object")] + pub s3_put_duration: Histogram, + + /// Total events processed. + #[metric(describe = "Total events processed")] + pub events_processed: Counter, + + /// Total S3 writes skipped due to deduplication. + #[metric(describe = "Total S3 writes skipped due to dedup")] + pub s3_writes_skipped: Counter, + + /// Number of in-flight archive tasks. + #[metric(describe = "Number of in-flight archive tasks")] + pub in_flight_archive_tasks: Gauge, + + /// Number of failed archive tasks. + #[metric(describe = "Number of failed archive tasks")] + pub failed_archive_tasks: Counter, +} diff --git a/crates/audit/src/publisher.rs b/crates/audit/src/publisher.rs new file mode 100644 index 0000000..b845f14 --- /dev/null +++ b/crates/audit/src/publisher.rs @@ -0,0 +1,228 @@ +use anyhow::Result; +use async_trait::async_trait; +use rdkafka::producer::{FutureProducer, FutureRecord}; +use tracing::{debug, error, info}; + +use crate::types::{BundleEvent, UserOpEvent}; + +/// Trait for publishing bundle events. +#[async_trait] +pub trait BundleEventPublisher: Send + Sync { + /// Publishes a single bundle event. + async fn publish(&self, event: BundleEvent) -> Result<()>; + + /// Publishes multiple bundle events. + async fn publish_all(&self, events: Vec) -> Result<()>; +} + +/// Publishes bundle events to Kafka. +#[derive(Clone)] +pub struct KafkaBundleEventPublisher { + producer: FutureProducer, + topic: String, +} + +impl std::fmt::Debug for KafkaBundleEventPublisher { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("KafkaBundleEventPublisher") + .field("topic", &self.topic) + .finish_non_exhaustive() + } +} + +impl KafkaBundleEventPublisher { + /// Creates a new Kafka bundle event publisher. + pub const fn new(producer: FutureProducer, topic: String) -> Self { + Self { producer, topic } + } + + async fn send_event(&self, event: &BundleEvent) -> Result<()> { + let bundle_id = event.bundle_id(); + let key = event.generate_event_key(); + let payload = serde_json::to_vec(event)?; + + let record = FutureRecord::to(&self.topic).key(&key).payload(&payload); + + match self.producer.send(record, tokio::time::Duration::from_secs(5)).await { + Ok(_) => { + debug!( + bundle_id = %bundle_id, + topic = %self.topic, + payload_size = payload.len(), + "successfully published event" + ); + Ok(()) + } + Err((err, _)) => { + error!( + bundle_id = %bundle_id, + topic = %self.topic, + error = %err, + "failed to publish event" + ); + Err(anyhow::anyhow!("Failed to publish event: {err}")) + } + } + } +} + +#[async_trait] +impl BundleEventPublisher for KafkaBundleEventPublisher { + async fn publish(&self, event: BundleEvent) -> Result<()> { + self.send_event(&event).await + } + + async fn publish_all(&self, events: Vec) -> Result<()> { + for event in events { + self.send_event(&event).await?; + } + Ok(()) + } +} + +/// Publishes bundle events to logs (for testing/debugging). +#[derive(Clone, Debug)] +pub struct LoggingBundleEventPublisher; + +impl LoggingBundleEventPublisher { + /// Creates a new logging bundle event publisher. + pub const fn new() -> Self { + Self + } +} + +impl Default for LoggingBundleEventPublisher { + fn default() -> Self { + Self::new() + } +} + +#[async_trait] +impl BundleEventPublisher for LoggingBundleEventPublisher { + async fn publish(&self, event: BundleEvent) -> Result<()> { + info!( + bundle_id = %event.bundle_id(), + event = ?event, + "Received bundle event" + ); + Ok(()) + } + + async fn publish_all(&self, events: Vec) -> Result<()> { + for event in events { + self.publish(event).await?; + } + Ok(()) + } +} + +/// Trait for publishing user operation events. +#[async_trait] +pub trait UserOpEventPublisher: Send + Sync { + /// Publishes a single user operation event. + async fn publish(&self, event: UserOpEvent) -> Result<()>; + + /// Publishes multiple user operation events. + async fn publish_all(&self, events: Vec) -> Result<()>; +} + +/// Publishes user operation events to Kafka. +#[derive(Clone)] +pub struct KafkaUserOpEventPublisher { + producer: FutureProducer, + topic: String, +} + +impl std::fmt::Debug for KafkaUserOpEventPublisher { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("KafkaUserOpEventPublisher") + .field("topic", &self.topic) + .finish_non_exhaustive() + } +} + +impl KafkaUserOpEventPublisher { + /// Creates a new Kafka user operation event publisher. + pub const fn new(producer: FutureProducer, topic: String) -> Self { + Self { producer, topic } + } + + async fn send_event(&self, event: &UserOpEvent) -> Result<()> { + let user_op_hash = event.user_op_hash(); + let key = event.generate_event_key(); + let payload = serde_json::to_vec(event)?; + + let record = FutureRecord::to(&self.topic).key(&key).payload(&payload); + + match self.producer.send(record, tokio::time::Duration::from_secs(5)).await { + Ok(_) => { + debug!( + user_op_hash = %user_op_hash, + topic = %self.topic, + payload_size = payload.len(), + "Successfully published user op event" + ); + Ok(()) + } + Err((err, _)) => { + error!( + user_op_hash = %user_op_hash, + topic = %self.topic, + error = %err, + "Failed to publish user op event" + ); + Err(anyhow::anyhow!("Failed to publish user op event: {err}")) + } + } + } +} + +#[async_trait] +impl UserOpEventPublisher for KafkaUserOpEventPublisher { + async fn publish(&self, event: UserOpEvent) -> Result<()> { + self.send_event(&event).await + } + + async fn publish_all(&self, events: Vec) -> Result<()> { + for event in events { + self.send_event(&event).await?; + } + Ok(()) + } +} + +/// Publishes user operation events to logs (for testing/debugging). +#[derive(Clone, Debug)] +pub struct LoggingUserOpEventPublisher; + +impl LoggingUserOpEventPublisher { + /// Creates a new logging user operation event publisher. + pub const fn new() -> Self { + Self + } +} + +impl Default for LoggingUserOpEventPublisher { + fn default() -> Self { + Self::new() + } +} + +#[async_trait] +impl UserOpEventPublisher for LoggingUserOpEventPublisher { + async fn publish(&self, event: UserOpEvent) -> Result<()> { + info!( + user_op_hash = %event.user_op_hash(), + event = ?event, + "Received user op event" + ); + Ok(()) + } + + async fn publish_all(&self, events: Vec) -> Result<()> { + for event in events { + self.publish(event).await?; + } + Ok(()) + } +} diff --git a/crates/audit/src/reader.rs b/crates/audit/src/reader.rs new file mode 100644 index 0000000..f447a96 --- /dev/null +++ b/crates/audit/src/reader.rs @@ -0,0 +1,246 @@ +use std::time::{Duration, SystemTime, UNIX_EPOCH}; + +use anyhow::Result; +use async_trait::async_trait; +use rdkafka::{ + Timestamp, TopicPartitionList, + config::ClientConfig, + consumer::{Consumer, StreamConsumer}, + message::Message, +}; +use tokio::time::sleep; +use tracing::{debug, error, info}; +use utils::kafka::load_kafka_config_from_file; + +use crate::types::{BundleEvent, UserOpEvent}; + +/// Creates a Kafka consumer from a properties file. +pub fn create_kafka_consumer(kafka_properties_file: &str) -> Result { + let client_config: ClientConfig = + ClientConfig::from_iter(load_kafka_config_from_file(kafka_properties_file)?); + let consumer: StreamConsumer = client_config.create()?; + Ok(consumer) +} + +/// Assigns a topic partition to a consumer. +pub fn assign_topic_partition(consumer: &StreamConsumer, topic: &str) -> Result<()> { + let mut tpl = TopicPartitionList::new(); + tpl.add_partition(topic, 0); + consumer.assign(&tpl)?; + Ok(()) +} + +/// A bundle event with metadata from Kafka. +#[derive(Debug, Clone)] +pub struct Event { + /// The event key. + pub key: String, + /// The bundle event. + pub event: BundleEvent, + /// The event timestamp in milliseconds. + pub timestamp: i64, +} + +/// Trait for reading bundle events. +#[async_trait] +pub trait EventReader { + /// Reads the next event. + async fn read_event(&mut self) -> Result; + /// Commits the last read message. + async fn commit(&mut self) -> Result<()>; +} + +/// Reads bundle audit events from Kafka. +pub struct KafkaAuditLogReader { + consumer: StreamConsumer, + topic: String, + last_message_offset: Option, + last_message_partition: Option, +} + +impl std::fmt::Debug for KafkaAuditLogReader { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("KafkaAuditLogReader") + .field("topic", &self.topic) + .field("last_message_offset", &self.last_message_offset) + .field("last_message_partition", &self.last_message_partition) + .finish_non_exhaustive() + } +} + +impl KafkaAuditLogReader { + /// Creates a new Kafka audit log reader. + pub fn new(consumer: StreamConsumer, topic: String) -> Result { + consumer.subscribe(&[&topic])?; + Ok(Self { consumer, topic, last_message_offset: None, last_message_partition: None }) + } +} + +#[async_trait] +impl EventReader for KafkaAuditLogReader { + async fn read_event(&mut self) -> Result { + match self.consumer.recv().await { + Ok(message) => { + let payload = + message.payload().ok_or_else(|| anyhow::anyhow!("Message has no payload"))?; + + // Extract Kafka timestamp, use current time as fallback + let timestamp = match message.timestamp() { + Timestamp::CreateTime(millis) | Timestamp::LogAppendTime(millis) => millis, + Timestamp::NotAvailable => { + SystemTime::now().duration_since(UNIX_EPOCH).unwrap_or_default().as_millis() + as i64 + } + }; + + let event: BundleEvent = serde_json::from_slice(payload)?; + + info!( + bundle_id = %event.bundle_id(), + tx_ids = ?event.transaction_ids(), + timestamp = timestamp, + offset = message.offset(), + partition = message.partition(), + "Received event with timestamp" + ); + + self.last_message_offset = Some(message.offset()); + self.last_message_partition = Some(message.partition()); + + let key = message + .key() + .map(|k| String::from_utf8_lossy(k).to_string()) + .ok_or_else(|| anyhow::anyhow!("Message missing required key"))?; + + let event_result = Event { key, event, timestamp }; + + Ok(event_result) + } + Err(e) => { + error!(error = %e, "Error receiving message from Kafka"); + sleep(Duration::from_secs(1)).await; + Err(e.into()) + } + } + } + + async fn commit(&mut self) -> Result<()> { + if let (Some(offset), Some(partition)) = + (self.last_message_offset, self.last_message_partition) + { + let mut tpl = TopicPartitionList::new(); + tpl.add_partition_offset(&self.topic, partition, rdkafka::Offset::Offset(offset + 1))?; + self.consumer.commit(&tpl, rdkafka::consumer::CommitMode::Async)?; + } + Ok(()) + } +} + +impl KafkaAuditLogReader { + /// Returns the topic this reader is subscribed to. + pub fn topic(&self) -> &str { + &self.topic + } +} + +/// A user operation event with metadata from Kafka. +#[derive(Debug, Clone)] +pub struct UserOpEventWrapper { + /// The event key. + pub key: String, + /// The user operation event. + pub event: UserOpEvent, + /// The event timestamp in milliseconds. + pub timestamp: i64, +} + +/// Trait for reading user operation events. +#[async_trait] +pub trait UserOpEventReader { + /// Reads the next user operation event. + async fn read_event(&mut self) -> Result; + /// Commits the last read message. + async fn commit(&mut self) -> Result<()>; +} + +/// Reads user operation audit events from Kafka. +pub struct KafkaUserOpAuditLogReader { + consumer: StreamConsumer, + topic: String, + last_message_offset: Option, + last_message_partition: Option, +} + +impl std::fmt::Debug for KafkaUserOpAuditLogReader { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("KafkaUserOpAuditLogReader") + .field("topic", &self.topic) + .field("last_message_offset", &self.last_message_offset) + .field("last_message_partition", &self.last_message_partition) + .finish_non_exhaustive() + } +} + +impl KafkaUserOpAuditLogReader { + /// Creates a new Kafka user operation audit log reader. + pub fn new(consumer: StreamConsumer, topic: String) -> Result { + consumer.subscribe(&[&topic])?; + Ok(Self { consumer, topic, last_message_offset: None, last_message_partition: None }) + } +} + +#[async_trait] +impl UserOpEventReader for KafkaUserOpAuditLogReader { + async fn read_event(&mut self) -> Result { + match self.consumer.recv().await { + Ok(message) => { + let payload = + message.payload().ok_or_else(|| anyhow::anyhow!("Message has no payload"))?; + + let timestamp = match message.timestamp() { + Timestamp::CreateTime(millis) | Timestamp::LogAppendTime(millis) => millis, + Timestamp::NotAvailable => { + SystemTime::now().duration_since(UNIX_EPOCH).unwrap_or_default().as_millis() + as i64 + } + }; + + let event: UserOpEvent = serde_json::from_slice(payload)?; + + debug!( + user_op_hash = %event.user_op_hash(), + timestamp = timestamp, + offset = message.offset(), + partition = message.partition(), + "Received UserOp event" + ); + + self.last_message_offset = Some(message.offset()); + self.last_message_partition = Some(message.partition()); + + let key = message + .key() + .map(|k| String::from_utf8_lossy(k).to_string()) + .ok_or_else(|| anyhow::anyhow!("Message missing required key"))?; + + Ok(UserOpEventWrapper { key, event, timestamp }) + } + Err(e) => { + error!(error = %e, "Error receiving UserOp message from Kafka"); + sleep(Duration::from_secs(1)).await; + Err(e.into()) + } + } + } + + async fn commit(&mut self) -> Result<()> { + if let (Some(offset), Some(partition)) = + (self.last_message_offset, self.last_message_partition) + { + let mut tpl = TopicPartitionList::new(); + tpl.add_partition_offset(&self.topic, partition, rdkafka::Offset::Offset(offset + 1))?; + self.consumer.commit(&tpl, rdkafka::consumer::CommitMode::Async)?; + } + Ok(()) + } +} diff --git a/crates/audit/src/storage.rs b/crates/audit/src/storage.rs new file mode 100644 index 0000000..3c15ce1 --- /dev/null +++ b/crates/audit/src/storage.rs @@ -0,0 +1,925 @@ +use std::{fmt, fmt::Debug, time::Instant}; + +use alloy_primitives::{Address, TxHash, U256}; +use anyhow::Result; +use async_trait::async_trait; +use aws_sdk_s3::{ + Client as S3Client, error::SdkError, operation::get_object::GetObjectError, + primitives::ByteStream, +}; +use base_bundles::AcceptedBundle; +use futures::future; +use serde::{Deserialize, Serialize}; +use tracing::info; + +use crate::{ + metrics::Metrics, + reader::Event, + types::{ + BundleEvent, BundleId, DropReason, TransactionId, UserOpDropReason, UserOpEvent, UserOpHash, + }, +}; + +/// S3 key types for storing different event types. +#[derive(Debug)] +pub enum S3Key { + /// Key for bundle events. + Bundle(BundleId), + /// Key for transaction lookups by hash. + TransactionByHash(TxHash), + /// Key for user operation events. + UserOp(UserOpHash), +} + +impl fmt::Display for S3Key { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Bundle(bundle_id) => write!(f, "bundles/{bundle_id}"), + Self::TransactionByHash(hash) => write!(f, "transactions/by_hash/{hash}"), + Self::UserOp(user_op_hash) => write!(f, "userops/{user_op_hash}"), + } + } +} + +/// Metadata for a transaction, tracking which bundles it belongs to. +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +pub struct TransactionMetadata { + /// Bundle IDs that contain this transaction. + pub bundle_ids: Vec, +} + +/// History event for a bundle. +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(tag = "event", content = "data")] +pub enum BundleHistoryEvent { + /// Bundle was received. + Received { + /// Event key. + key: String, + /// Event timestamp. + timestamp: i64, + /// The accepted bundle. + bundle: Box, + }, + /// Bundle was cancelled. + Cancelled { + /// Event key. + key: String, + /// Event timestamp. + timestamp: i64, + }, + /// Bundle was included by a builder. + BuilderIncluded { + /// Event key. + key: String, + /// Event timestamp. + timestamp: i64, + /// Builder identifier. + builder: String, + /// Block number. + block_number: u64, + /// Flashblock index. + flashblock_index: u64, + }, + /// Bundle was included in a block. + BlockIncluded { + /// Event key. + key: String, + /// Event timestamp. + timestamp: i64, + /// Block number. + block_number: u64, + /// Block hash. + block_hash: TxHash, + }, + /// Bundle was dropped. + Dropped { + /// Event key. + key: String, + /// Event timestamp. + timestamp: i64, + /// Drop reason. + reason: DropReason, + }, +} + +impl BundleHistoryEvent { + /// Returns the event key. + pub fn key(&self) -> &str { + match self { + Self::Received { key, .. } + | Self::Cancelled { key, .. } + | Self::BuilderIncluded { key, .. } + | Self::BlockIncluded { key, .. } + | Self::Dropped { key, .. } => key, + } + } +} + +/// History of events for a bundle. +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +pub struct BundleHistory { + /// List of history events. + pub history: Vec, +} + +/// History event for a user operation. +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(tag = "event", content = "data")] +pub enum UserOpHistoryEvent { + /// User operation was added to the mempool. + AddedToMempool { + /// Event key. + key: String, + /// Event timestamp. + timestamp: i64, + /// Sender address. + sender: Address, + /// Entry point address. + entry_point: Address, + /// Nonce. + nonce: U256, + }, + /// User operation was dropped. + Dropped { + /// Event key. + key: String, + /// Event timestamp. + timestamp: i64, + /// Drop reason. + reason: UserOpDropReason, + }, + /// User operation was included in a block. + Included { + /// Event key. + key: String, + /// Event timestamp. + timestamp: i64, + /// Block number. + block_number: u64, + /// Transaction hash. + tx_hash: TxHash, + }, +} + +impl UserOpHistoryEvent { + /// Returns the event key. + pub fn key(&self) -> &str { + match self { + Self::AddedToMempool { key, .. } + | Self::Dropped { key, .. } + | Self::Included { key, .. } => key, + } + } +} + +/// History of events for a user operation. +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +pub struct UserOpHistory { + /// List of history events. + pub history: Vec, +} + +pub(crate) use crate::reader::UserOpEventWrapper; + +fn update_bundle_history_transform( + bundle_history: BundleHistory, + event: &Event, +) -> Option { + let mut history = bundle_history.history; + let bundle_id = event.event.bundle_id(); + + // Check for deduplication - if event with same key already exists, skip + if history.iter().any(|h| h.key() == event.key) { + info!( + bundle_id = %bundle_id, + event_key = %event.key, + "Event already exists, skipping due to deduplication" + ); + return None; + } + + let history_event = match &event.event { + BundleEvent::Received { bundle, .. } => BundleHistoryEvent::Received { + key: event.key.clone(), + timestamp: event.timestamp, + bundle: bundle.clone(), + }, + BundleEvent::Cancelled { .. } => { + BundleHistoryEvent::Cancelled { key: event.key.clone(), timestamp: event.timestamp } + } + BundleEvent::BuilderIncluded { builder, block_number, flashblock_index, .. } => { + BundleHistoryEvent::BuilderIncluded { + key: event.key.clone(), + timestamp: event.timestamp, + builder: builder.clone(), + block_number: *block_number, + flashblock_index: *flashblock_index, + } + } + BundleEvent::BlockIncluded { block_number, block_hash, .. } => { + BundleHistoryEvent::BlockIncluded { + key: event.key.clone(), + timestamp: event.timestamp, + block_number: *block_number, + block_hash: *block_hash, + } + } + BundleEvent::Dropped { reason, .. } => BundleHistoryEvent::Dropped { + key: event.key.clone(), + timestamp: event.timestamp, + reason: reason.clone(), + }, + }; + + history.push(history_event); + let bundle_history = BundleHistory { history }; + + info!( + bundle_id = %bundle_id, + event_count = bundle_history.history.len(), + "Updated bundle history" + ); + + Some(bundle_history) +} + +fn update_transaction_metadata_transform( + transaction_metadata: TransactionMetadata, + bundle_id: BundleId, +) -> Option { + let mut bundle_ids = transaction_metadata.bundle_ids; + + if bundle_ids.contains(&bundle_id) { + return None; + } + + bundle_ids.push(bundle_id); + Some(TransactionMetadata { bundle_ids }) +} + +fn update_userop_history_transform( + userop_history: UserOpHistory, + event: &UserOpEventWrapper, +) -> Option { + let mut history = userop_history.history; + let user_op_hash = event.event.user_op_hash(); + + if history.iter().any(|h| h.key() == event.key) { + info!( + user_op_hash = %user_op_hash, + event_key = %event.key, + "UserOp event already exists, skipping due to deduplication" + ); + return None; + } + + let history_event = match &event.event { + UserOpEvent::AddedToMempool { sender, entry_point, nonce, .. } => { + UserOpHistoryEvent::AddedToMempool { + key: event.key.clone(), + timestamp: event.timestamp, + sender: *sender, + entry_point: *entry_point, + nonce: *nonce, + } + } + UserOpEvent::Dropped { reason, .. } => UserOpHistoryEvent::Dropped { + key: event.key.clone(), + timestamp: event.timestamp, + reason: reason.clone(), + }, + UserOpEvent::Included { block_number, tx_hash, .. } => UserOpHistoryEvent::Included { + key: event.key.clone(), + timestamp: event.timestamp, + block_number: *block_number, + tx_hash: *tx_hash, + }, + }; + + history.push(history_event); + let userop_history = UserOpHistory { history }; + + info!( + user_op_hash = %user_op_hash, + event_count = userop_history.history.len(), + "Updated user op history" + ); + + Some(userop_history) +} + +/// Trait for writing bundle events to storage. +#[async_trait] +pub trait EventWriter { + /// Archives a bundle event. + async fn archive_event(&self, event: Event) -> Result<()>; +} + +/// Trait for writing user operation events to storage. +#[async_trait] +pub trait UserOpEventWriter { + /// Archives a user operation event. + async fn archive_userop_event(&self, event: UserOpEventWrapper) -> Result<()>; +} + +/// Trait for reading bundle events from S3. +#[async_trait] +pub trait BundleEventS3Reader { + /// Gets the bundle history for a given bundle ID. + async fn get_bundle_history(&self, bundle_id: BundleId) -> Result>; + /// Gets transaction metadata for a given transaction hash. + async fn get_transaction_metadata( + &self, + tx_hash: TxHash, + ) -> Result>; +} + +/// Trait for reading user operation events from S3. +#[async_trait] +pub trait UserOpEventS3Reader { + /// Gets the user operation history for a given hash. + async fn get_userop_history(&self, user_op_hash: UserOpHash) -> Result>; +} + +/// S3-backed event reader and writer. +#[derive(Clone, Debug)] +pub struct S3EventReaderWriter { + s3_client: S3Client, + bucket: String, + metrics: Metrics, +} + +impl S3EventReaderWriter { + /// Creates a new S3 event reader/writer. + pub fn new(s3_client: S3Client, bucket: String) -> Self { + Self { s3_client, bucket, metrics: Metrics::default() } + } + + async fn update_bundle_history(&self, event: Event) -> Result<()> { + let s3_key = S3Key::Bundle(event.event.bundle_id()).to_string(); + + self.idempotent_write::(&s3_key, |current_history| { + update_bundle_history_transform(current_history, &event) + }) + .await + } + + async fn update_transaction_by_hash_index( + &self, + tx_id: &TransactionId, + bundle_id: BundleId, + ) -> Result<()> { + let s3_key = S3Key::TransactionByHash(tx_id.hash); + let key = s3_key.to_string(); + + self.idempotent_write::(&key, |current_metadata| { + update_transaction_metadata_transform(current_metadata, bundle_id) + }) + .await + } + + async fn update_userop_history(&self, event: UserOpEventWrapper) -> Result<()> { + let s3_key = S3Key::UserOp(event.event.user_op_hash()).to_string(); + + self.idempotent_write::(&s3_key, |current_history| { + update_userop_history_transform(current_history, &event) + }) + .await + } + + async fn idempotent_write(&self, key: &str, mut transform_fn: F) -> Result<()> + where + T: for<'de> Deserialize<'de> + Serialize + Clone + Default + Debug, + F: FnMut(T) -> Option, + { + const MAX_RETRIES: usize = 5; + const BASE_DELAY_MS: u64 = 100; + + for attempt in 0..MAX_RETRIES { + let get_start = Instant::now(); + let (current_value, etag) = self.get_object_with_etag::(key).await?; + self.metrics.s3_get_duration.record(get_start.elapsed().as_secs_f64()); + + let value = current_value.unwrap_or_default(); + + match transform_fn(value.clone()) { + Some(new_value) => { + let content = serde_json::to_string(&new_value)?; + + let mut put_request = self + .s3_client + .put_object() + .bucket(&self.bucket) + .key(key) + .body(ByteStream::from(content.into_bytes())); + + if let Some(etag) = etag { + put_request = put_request.if_match(etag); + } else { + put_request = put_request.if_none_match("*"); + } + + let put_start = Instant::now(); + match put_request.send().await { + Ok(_) => { + self.metrics.s3_put_duration.record(put_start.elapsed().as_secs_f64()); + info!( + s3_key = %key, + attempt = attempt + 1, + "Successfully wrote object with idempotent write" + ); + return Ok(()); + } + Err(e) => { + self.metrics.s3_put_duration.record(put_start.elapsed().as_secs_f64()); + + if attempt < MAX_RETRIES - 1 { + let delay = BASE_DELAY_MS * 2_u64.pow(attempt as u32); + info!( + s3_key = %key, + attempt = attempt + 1, + delay_ms = delay, + error = %e, + "Conflict detected, retrying with backoff" + ); + tokio::time::sleep(tokio::time::Duration::from_millis(delay)).await; + } else { + return Err(anyhow::anyhow!( + "Failed to write after {MAX_RETRIES} attempts: {e}" + )); + } + } + } + } + None => { + self.metrics.s3_writes_skipped.increment(1); + info!( + s3_key = %key, + "Transform function returned None, no write required" + ); + return Ok(()); + } + } + } + + Err(anyhow::anyhow!("Exceeded maximum retry attempts")) + } + + async fn get_object_with_etag(&self, key: &str) -> Result<(Option, Option)> + where + T: for<'de> Deserialize<'de>, + { + match self.s3_client.get_object().bucket(&self.bucket).key(key).send().await { + Ok(response) => { + let etag = response.e_tag().map(|s| s.to_string()); + let body = response.body.collect().await?; + let content = String::from_utf8(body.into_bytes().to_vec())?; + let value: T = serde_json::from_str(&content)?; + Ok((Some(value), etag)) + } + Err(e) => match &e { + SdkError::ServiceError(service_err) => match service_err.err() { + GetObjectError::NoSuchKey(_) => Ok((None, None)), + _ => Err(anyhow::anyhow!("Failed to get object: {e}")), + }, + _ => { + let error_string = e.to_string(); + if error_string.contains("NoSuchKey") + || error_string.contains("NotFound") + || error_string.contains("404") + { + Ok((None, None)) + } else { + Err(anyhow::anyhow!("Failed to get object: {e}")) + } + } + }, + } + } +} + +#[async_trait] +impl EventWriter for S3EventReaderWriter { + async fn archive_event(&self, event: Event) -> Result<()> { + let bundle_id = event.event.bundle_id(); + let transaction_ids = event.event.transaction_ids(); + + let bundle_start = Instant::now(); + let bundle_future = self.update_bundle_history(event); + + let tx_start = Instant::now(); + let tx_futures: Vec<_> = + transaction_ids + .into_iter() + .map(|tx_id| async move { + self.update_transaction_by_hash_index(&tx_id, bundle_id).await + }) + .collect(); + + // Run the bundle and transaction futures concurrently and wait for them to complete + tokio::try_join!(bundle_future, future::try_join_all(tx_futures))?; + + self.metrics.update_bundle_history_duration.record(bundle_start.elapsed().as_secs_f64()); + self.metrics.update_tx_indexes_duration.record(tx_start.elapsed().as_secs_f64()); + + Ok(()) + } +} + +#[async_trait] +impl BundleEventS3Reader for S3EventReaderWriter { + async fn get_bundle_history(&self, bundle_id: BundleId) -> Result> { + let s3_key = S3Key::Bundle(bundle_id).to_string(); + let (bundle_history, _) = self.get_object_with_etag::(&s3_key).await?; + Ok(bundle_history) + } + + async fn get_transaction_metadata( + &self, + tx_hash: TxHash, + ) -> Result> { + let s3_key = S3Key::TransactionByHash(tx_hash).to_string(); + let (transaction_metadata, _) = + self.get_object_with_etag::(&s3_key).await?; + Ok(transaction_metadata) + } +} + +#[async_trait] +impl UserOpEventWriter for S3EventReaderWriter { + async fn archive_userop_event(&self, event: UserOpEventWrapper) -> Result<()> { + self.update_userop_history(event).await + } +} + +#[async_trait] +impl UserOpEventS3Reader for S3EventReaderWriter { + async fn get_userop_history(&self, user_op_hash: UserOpHash) -> Result> { + let s3_key = S3Key::UserOp(user_op_hash).to_string(); + let (userop_history, _) = self.get_object_with_etag::(&s3_key).await?; + Ok(userop_history) + } +} + +#[cfg(test)] +mod tests { + use alloy_primitives::{Address, B256, TxHash, U256}; + use base_bundles::BundleExtensions; + use uuid::Uuid; + + use super::*; + use crate::{ + reader::Event, + test_utils::create_bundle_from_txn_data, + types::{BundleEvent, DropReason, UserOpDropReason, UserOpEvent}, + }; + + fn create_test_event(key: &str, timestamp: i64, bundle_event: BundleEvent) -> Event { + Event { key: key.to_string(), timestamp, event: bundle_event } + } + + #[test] + fn test_update_bundle_history_transform_adds_new_event() { + let bundle_history = BundleHistory { history: vec![] }; + let bundle = create_bundle_from_txn_data(); + let bundle_id = Uuid::new_v5(&Uuid::NAMESPACE_OID, bundle.bundle_hash().as_slice()); + let bundle_event = BundleEvent::Received { bundle_id, bundle: Box::new(bundle.clone()) }; + let event = create_test_event("test-key", 1234567890, bundle_event); + + let result = update_bundle_history_transform(bundle_history, &event); + + assert!(result.is_some()); + let bundle_history = result.unwrap(); + assert_eq!(bundle_history.history.len(), 1); + + match &bundle_history.history[0] { + BundleHistoryEvent::Received { key, timestamp: ts, bundle: b } => { + assert_eq!(key, "test-key"); + assert_eq!(*ts, 1234567890); + assert_eq!(b.block_number, bundle.block_number); + } + _ => panic!("Expected Created event"), + } + } + + #[test] + fn test_update_bundle_history_transform_skips_duplicate_key() { + let existing_event = BundleHistoryEvent::Received { + key: "duplicate-key".to_string(), + timestamp: 1111111111, + bundle: Box::new(create_bundle_from_txn_data()), + }; + let bundle_history = BundleHistory { history: vec![existing_event] }; + + let bundle = create_bundle_from_txn_data(); + let bundle_id = Uuid::new_v5(&Uuid::NAMESPACE_OID, bundle.bundle_hash().as_slice()); + let bundle_event = BundleEvent::Received { bundle_id, bundle: Box::new(bundle) }; + let event = create_test_event("duplicate-key", 1234567890, bundle_event); + + let result = update_bundle_history_transform(bundle_history, &event); + + assert!(result.is_none()); + } + + #[test] + fn test_update_bundle_history_transform_handles_all_event_types() { + let bundle_history = BundleHistory { history: vec![] }; + let bundle = create_bundle_from_txn_data(); + let bundle_id = Uuid::new_v5(&Uuid::NAMESPACE_OID, bundle.bundle_hash().as_slice()); + + let bundle_event = BundleEvent::Received { bundle_id, bundle: Box::new(bundle) }; + let event = create_test_event("test-key", 1234567890, bundle_event); + let result = update_bundle_history_transform(bundle_history.clone(), &event); + assert!(result.is_some()); + + let bundle_event = BundleEvent::Cancelled { bundle_id }; + let event = create_test_event("test-key-2", 1234567890, bundle_event); + let result = update_bundle_history_transform(bundle_history.clone(), &event); + assert!(result.is_some()); + + let bundle_event = BundleEvent::BuilderIncluded { + bundle_id, + builder: "test-builder".to_string(), + block_number: 12345, + flashblock_index: 1, + }; + let event = create_test_event("test-key-3", 1234567890, bundle_event); + let result = update_bundle_history_transform(bundle_history.clone(), &event); + assert!(result.is_some()); + + let bundle_event = BundleEvent::BlockIncluded { + bundle_id, + block_number: 12345, + block_hash: TxHash::from([1u8; 32]), + }; + let event = create_test_event("test-key-4", 1234567890, bundle_event); + let result = update_bundle_history_transform(bundle_history.clone(), &event); + assert!(result.is_some()); + + let bundle_event = BundleEvent::Dropped { bundle_id, reason: DropReason::TimedOut }; + let event = create_test_event("test-key-5", 1234567890, bundle_event); + let result = update_bundle_history_transform(bundle_history, &event); + assert!(result.is_some()); + } + + #[test] + fn test_update_transaction_metadata_transform_adds_new_bundle() { + let metadata = TransactionMetadata { bundle_ids: vec![] }; + let bundle = create_bundle_from_txn_data(); + let bundle_id = Uuid::new_v5(&Uuid::NAMESPACE_OID, bundle.bundle_hash().as_slice()); + + let result = update_transaction_metadata_transform(metadata, bundle_id); + + assert!(result.is_some()); + let metadata = result.unwrap(); + assert_eq!(metadata.bundle_ids.len(), 1); + assert_eq!(metadata.bundle_ids[0], bundle_id); + } + + #[test] + fn test_update_transaction_metadata_transform_skips_existing_bundle() { + let bundle = create_bundle_from_txn_data(); + let bundle_id = Uuid::new_v5(&Uuid::NAMESPACE_OID, bundle.bundle_hash().as_slice()); + let metadata = TransactionMetadata { bundle_ids: vec![bundle_id] }; + + let result = update_transaction_metadata_transform(metadata, bundle_id); + + assert!(result.is_none()); + } + + #[test] + fn test_update_transaction_metadata_transform_adds_to_existing_bundles() { + // Some different, dummy bundle IDs since create_bundle_from_txn_data() returns the same bundle ID + // Even if the same txn is contained across multiple bundles, the bundle ID will be different since the + // UUID is based on the bundle hash. + let existing_bundle_id = Uuid::parse_str("550e8400-e29b-41d4-a716-446655440000").unwrap(); + let new_bundle_id = Uuid::parse_str("6ba7b810-9dad-11d1-80b4-00c04fd430c8").unwrap(); + + let metadata = TransactionMetadata { bundle_ids: vec![existing_bundle_id] }; + + let result = update_transaction_metadata_transform(metadata, new_bundle_id); + + assert!(result.is_some()); + let metadata = result.unwrap(); + assert_eq!(metadata.bundle_ids.len(), 2); + assert!(metadata.bundle_ids.contains(&existing_bundle_id)); + assert!(metadata.bundle_ids.contains(&new_bundle_id)); + } + + fn create_test_userop_event( + key: &str, + timestamp: i64, + userop_event: UserOpEvent, + ) -> UserOpEventWrapper { + UserOpEventWrapper { key: key.to_string(), timestamp, event: userop_event } + } + + #[test] + fn test_s3_key_userop_display() { + let hash = B256::from([1u8; 32]); + let key = S3Key::UserOp(hash); + let key_str = key.to_string(); + assert!(key_str.starts_with("userops/")); + assert!(key_str.contains(&format!("{hash}"))); + } + + #[test] + fn test_update_userop_history_transform_adds_new_event() { + let userop_history = UserOpHistory { history: vec![] }; + let user_op_hash = B256::from([1u8; 32]); + let sender = Address::from([2u8; 20]); + let entry_point = Address::from([3u8; 20]); + let nonce = U256::from(1); + + let userop_event = UserOpEvent::AddedToMempool { user_op_hash, sender, entry_point, nonce }; + let event = create_test_userop_event("test-key", 1234567890, userop_event); + + let result = update_userop_history_transform(userop_history, &event); + + assert!(result.is_some()); + let history = result.unwrap(); + assert_eq!(history.history.len(), 1); + + match &history.history[0] { + UserOpHistoryEvent::AddedToMempool { + key, + timestamp: ts, + sender: s, + entry_point: ep, + nonce: n, + } => { + assert_eq!(key, "test-key"); + assert_eq!(*ts, 1234567890); + assert_eq!(*s, sender); + assert_eq!(*ep, entry_point); + assert_eq!(*n, nonce); + } + _ => panic!("Expected AddedToMempool event"), + } + } + + #[test] + fn test_update_userop_history_transform_skips_duplicate_key() { + let user_op_hash = B256::from([1u8; 32]); + let sender = Address::from([2u8; 20]); + let entry_point = Address::from([3u8; 20]); + let nonce = U256::from(1); + + let existing_event = UserOpHistoryEvent::AddedToMempool { + key: "duplicate-key".to_string(), + timestamp: 1111111111, + sender, + entry_point, + nonce, + }; + let userop_history = UserOpHistory { history: vec![existing_event] }; + + let userop_event = UserOpEvent::AddedToMempool { user_op_hash, sender, entry_point, nonce }; + let event = create_test_userop_event("duplicate-key", 1234567890, userop_event); + + let result = update_userop_history_transform(userop_history, &event); + + assert!(result.is_none()); + } + + #[test] + fn test_update_userop_history_transform_handles_dropped_event() { + let userop_history = UserOpHistory { history: vec![] }; + let user_op_hash = B256::from([1u8; 32]); + let reason = UserOpDropReason::Expired; + + let userop_event = UserOpEvent::Dropped { user_op_hash, reason }; + let event = create_test_userop_event("dropped-key", 1234567890, userop_event); + + let result = update_userop_history_transform(userop_history, &event); + + assert!(result.is_some()); + let history = result.unwrap(); + assert_eq!(history.history.len(), 1); + + match &history.history[0] { + UserOpHistoryEvent::Dropped { key, timestamp, reason: r } => { + assert_eq!(key, "dropped-key"); + assert_eq!(*timestamp, 1234567890); + match r { + UserOpDropReason::Expired => {} + _ => panic!("Expected Expired reason"), + } + } + _ => panic!("Expected Dropped event"), + } + } + + #[test] + fn test_update_userop_history_transform_handles_included_event() { + let userop_history = UserOpHistory { history: vec![] }; + let user_op_hash = B256::from([1u8; 32]); + let tx_hash = TxHash::from([4u8; 32]); + let block_number = 12345u64; + + let userop_event = UserOpEvent::Included { user_op_hash, block_number, tx_hash }; + let event = create_test_userop_event("included-key", 1234567890, userop_event); + + let result = update_userop_history_transform(userop_history, &event); + + assert!(result.is_some()); + let history = result.unwrap(); + assert_eq!(history.history.len(), 1); + + match &history.history[0] { + UserOpHistoryEvent::Included { key, timestamp, block_number: bn, tx_hash: th } => { + assert_eq!(key, "included-key"); + assert_eq!(*timestamp, 1234567890); + assert_eq!(*bn, 12345); + assert_eq!(*th, tx_hash); + } + _ => panic!("Expected Included event"), + } + } + + #[test] + fn test_update_userop_history_transform_handles_all_event_types() { + let userop_history = UserOpHistory { history: vec![] }; + let user_op_hash = B256::from([1u8; 32]); + let sender = Address::from([2u8; 20]); + let entry_point = Address::from([3u8; 20]); + let nonce = U256::from(1); + + let userop_event = UserOpEvent::AddedToMempool { user_op_hash, sender, entry_point, nonce }; + let event = create_test_userop_event("key-1", 1234567890, userop_event); + let result = update_userop_history_transform(userop_history.clone(), &event); + assert!(result.is_some()); + + let userop_event = UserOpEvent::Dropped { + user_op_hash, + reason: UserOpDropReason::Invalid("test error".to_string()), + }; + let event = create_test_userop_event("key-2", 1234567891, userop_event); + let result = update_userop_history_transform(userop_history.clone(), &event); + assert!(result.is_some()); + + let userop_event = UserOpEvent::Included { + user_op_hash, + block_number: 12345, + tx_hash: TxHash::from([4u8; 32]), + }; + let event = create_test_userop_event("key-3", 1234567892, userop_event); + let result = update_userop_history_transform(userop_history, &event); + assert!(result.is_some()); + } + + #[test] + fn test_userop_history_event_key_accessor() { + let sender = Address::from([2u8; 20]); + let entry_point = Address::from([3u8; 20]); + let nonce = U256::from(1); + + let event1 = UserOpHistoryEvent::AddedToMempool { + key: "key-1".to_string(), + timestamp: 1234567890, + sender, + entry_point, + nonce, + }; + assert_eq!(event1.key(), "key-1"); + + let event2 = UserOpHistoryEvent::Dropped { + key: "key-2".to_string(), + timestamp: 1234567890, + reason: UserOpDropReason::Expired, + }; + assert_eq!(event2.key(), "key-2"); + + let event3 = UserOpHistoryEvent::Included { + key: "key-3".to_string(), + timestamp: 1234567890, + block_number: 12345, + tx_hash: TxHash::from([4u8; 32]), + }; + assert_eq!(event3.key(), "key-3"); + } + + #[test] + fn test_userop_history_serialization() { + let sender = Address::from([2u8; 20]); + let entry_point = Address::from([3u8; 20]); + let nonce = U256::from(1); + + let history = UserOpHistory { + history: vec![UserOpHistoryEvent::AddedToMempool { + key: "test-key".to_string(), + timestamp: 1234567890, + sender, + entry_point, + nonce, + }], + }; + + let json = serde_json::to_string(&history).unwrap(); + let deserialized: UserOpHistory = serde_json::from_str(&json).unwrap(); + + assert_eq!(deserialized.history.len(), 1); + assert_eq!(deserialized.history[0].key(), "test-key"); + } +} diff --git a/crates/audit/src/test_utils.rs b/crates/audit/src/test_utils.rs new file mode 100644 index 0000000..5a34e48 --- /dev/null +++ b/crates/audit/src/test_utils.rs @@ -0,0 +1,76 @@ +//! Test utilities for creating bundles and transactions. + +use alloy_consensus::SignableTransaction; +use alloy_primitives::{Address, Bytes, TxHash, U256, b256, bytes}; +use alloy_provider::network::{TxSignerSync, eip2718::Encodable2718}; +use alloy_signer_local::PrivateKeySigner; +use base_bundles::{AcceptedBundle, Bundle, MeterBundleResponse}; +use op_alloy_consensus::OpTxEnvelope; +use op_alloy_rpc_types::OpTransactionRequest; + +// https://basescan.org/tx/0x4f7ddfc911f5cf85dd15a413f4cbb2a0abe4f1ff275ed13581958c0bcf043c5e +pub const TXN_DATA: Bytes = bytes!( + "0x02f88f8221058304b6b3018315fb3883124f80948ff2f0a8d017c79454aa28509a19ab9753c2dd1480a476d58e1a0182426068c9ea5b00000000000000000002f84f00000000083e4fda54950000c080a086fbc7bbee41f441fb0f32f7aa274d2188c460fe6ac95095fa6331fa08ec4ce7a01aee3bcc3c28f7ba4e0c24da9ae85e9e0166c73cabb42c25ff7b5ecd424f3105" +); + +pub const TXN_HASH: TxHash = + b256!("0x4f7ddfc911f5cf85dd15a413f4cbb2a0abe4f1ff275ed13581958c0bcf043c5e"); + +pub fn create_bundle_from_txn_data() -> AcceptedBundle { + AcceptedBundle::new( + Bundle { txs: vec![TXN_DATA], ..Default::default() }.try_into().unwrap(), + create_test_meter_bundle_response(), + ) +} + +pub fn create_transaction(from: PrivateKeySigner, nonce: u64, to: Address) -> OpTxEnvelope { + let mut txn = OpTransactionRequest::default() + .value(U256::from(10_000)) + .gas_limit(21_000) + .max_fee_per_gas(200) + .max_priority_fee_per_gas(100) + .from(from.address()) + .to(to) + .nonce(nonce) + .build_typed_tx() + .unwrap(); + + let sig = from.sign_transaction_sync(&mut txn).unwrap(); + OpTxEnvelope::Eip1559(txn.eip1559().cloned().unwrap().into_signed(sig)) +} + +pub fn create_test_bundle( + txns: Vec, + block_number: Option, + min_timestamp: Option, + max_timestamp: Option, +) -> AcceptedBundle { + let txs = txns.iter().map(|t| t.encoded_2718().into()).collect(); + + let bundle = Bundle { + txs, + block_number: block_number.unwrap_or(0), + min_timestamp, + max_timestamp, + ..Default::default() + }; + let meter_bundle_response = create_test_meter_bundle_response(); + + AcceptedBundle::new(bundle.try_into().unwrap(), meter_bundle_response) +} + +pub fn create_test_meter_bundle_response() -> MeterBundleResponse { + MeterBundleResponse { + bundle_gas_price: U256::from(0), + bundle_hash: alloy_primitives::B256::default(), + coinbase_diff: U256::from(0), + eth_sent_to_coinbase: U256::from(0), + gas_fees: U256::from(0), + results: vec![], + state_block_number: 0, + state_flashblock_index: None, + total_gas_used: 0, + total_execution_time_us: 0, + state_root_time_us: 0, + } +} diff --git a/crates/audit/src/types.rs b/crates/audit/src/types.rs new file mode 100644 index 0000000..96adb18 --- /dev/null +++ b/crates/audit/src/types.rs @@ -0,0 +1,318 @@ +use alloy_consensus::transaction::{SignerRecoverable, Transaction as ConsensusTransaction}; +use alloy_primitives::{Address, B256, TxHash, U256}; +use base_bundles::AcceptedBundle; +use bytes::Bytes; +use serde::{Deserialize, Serialize}; +use uuid::Uuid; + +/// Unique identifier for a transaction. +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub struct TransactionId { + /// The sender address. + pub sender: Address, + /// The transaction nonce. + pub nonce: U256, + /// The transaction hash. + pub hash: TxHash, +} + +/// Unique identifier for a bundle. +pub type BundleId = Uuid; + +/// Reason a bundle was dropped. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum DropReason { + /// Bundle timed out. + TimedOut, + /// Bundle transaction reverted. + Reverted, +} + +/// A transaction with its data. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Transaction { + /// Transaction identifier. + pub id: TransactionId, + /// Raw transaction data. + pub data: Bytes, +} + +/// Hash of a user operation. +pub type UserOpHash = B256; + +/// Reason a user operation was dropped. +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum UserOpDropReason { + /// User operation was invalid. + Invalid(String), + /// User operation expired. + Expired, + /// Replaced by a higher fee user operation. + ReplacedByHigherFee, +} + +/// Bundle lifecycle event. +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(tag = "event", content = "data")] +pub enum BundleEvent { + /// Bundle was received. + Received { + /// Bundle identifier. + bundle_id: BundleId, + /// The accepted bundle. + bundle: Box, + }, + /// Bundle was cancelled. + Cancelled { + /// Bundle identifier. + bundle_id: BundleId, + }, + /// Bundle was included by a builder. + BuilderIncluded { + /// Bundle identifier. + bundle_id: BundleId, + /// Builder identifier. + builder: String, + /// Block number. + block_number: u64, + /// Flashblock index. + flashblock_index: u64, + }, + /// Bundle was included in a block. + BlockIncluded { + /// Bundle identifier. + bundle_id: BundleId, + /// Block number. + block_number: u64, + /// Block hash. + block_hash: TxHash, + }, + /// Bundle was dropped. + Dropped { + /// Bundle identifier. + bundle_id: BundleId, + /// Drop reason. + reason: DropReason, + }, +} + +impl BundleEvent { + /// Returns the bundle ID for this event. + pub const fn bundle_id(&self) -> BundleId { + match self { + Self::Received { bundle_id, .. } + | Self::Cancelled { bundle_id, .. } + | Self::BuilderIncluded { bundle_id, .. } + | Self::BlockIncluded { bundle_id, .. } + | Self::Dropped { bundle_id, .. } => *bundle_id, + } + } + + /// Returns transaction IDs from this event (only for Received events). + pub fn transaction_ids(&self) -> Vec { + match self { + Self::Received { bundle, .. } => bundle + .txs + .iter() + .filter_map(|envelope| { + envelope.recover_signer().ok().map(|sender| TransactionId { + sender, + nonce: U256::from(envelope.nonce()), + hash: *envelope.hash(), + }) + }) + .collect(), + Self::Cancelled { .. } + | Self::BuilderIncluded { .. } + | Self::BlockIncluded { .. } + | Self::Dropped { .. } => vec![], + } + } + + /// Generates a unique event key for this event. + pub fn generate_event_key(&self) -> String { + match self { + Self::BlockIncluded { bundle_id, block_hash, .. } => { + format!("{bundle_id}-{block_hash}") + } + _ => { + format!( + "{}-{}", + self.bundle_id(), + Uuid::new_v5(&Uuid::NAMESPACE_OID, self.bundle_id().as_bytes()) + ) + } + } + } +} + +/// User operation lifecycle event. +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(tag = "event", content = "data")] +pub enum UserOpEvent { + /// User operation was added to the mempool. + AddedToMempool { + /// Hash of the user operation. + user_op_hash: UserOpHash, + /// Sender address. + sender: Address, + /// Entry point address. + entry_point: Address, + /// Nonce. + nonce: U256, + }, + /// User operation was dropped. + Dropped { + /// Hash of the user operation. + user_op_hash: UserOpHash, + /// Reason for dropping. + reason: UserOpDropReason, + }, + /// User operation was included in a block. + Included { + /// Hash of the user operation. + user_op_hash: UserOpHash, + /// Block number. + block_number: u64, + /// Transaction hash. + tx_hash: TxHash, + }, +} + +impl UserOpEvent { + /// Returns the user operation hash for this event. + pub const fn user_op_hash(&self) -> UserOpHash { + match self { + Self::AddedToMempool { user_op_hash, .. } + | Self::Dropped { user_op_hash, .. } + | Self::Included { user_op_hash, .. } => *user_op_hash, + } + } + + /// Generates a unique event key for this event. + pub fn generate_event_key(&self) -> String { + match self { + Self::Included { user_op_hash, tx_hash, .. } => { + format!("{user_op_hash}-{tx_hash}") + } + _ => { + format!( + "{}-{}", + self.user_op_hash(), + Uuid::new_v5(&Uuid::NAMESPACE_OID, self.user_op_hash().as_slice()) + ) + } + } + } +} + +#[cfg(test)] +mod user_op_event_tests { + use alloy_primitives::{address, b256}; + + use super::*; + + fn create_test_user_op_hash() -> UserOpHash { + b256!("1111111111111111111111111111111111111111111111111111111111111111") + } + + #[test] + fn test_user_op_event_added_to_mempool_serialization() { + let event = UserOpEvent::AddedToMempool { + user_op_hash: create_test_user_op_hash(), + sender: address!("2222222222222222222222222222222222222222"), + entry_point: address!("0000000071727De22E5E9d8BAf0edAc6f37da032"), + nonce: U256::from(1), + }; + + let json = serde_json::to_string(&event).unwrap(); + assert!(json.contains("\"event\":\"AddedToMempool\"")); + + let deserialized: UserOpEvent = serde_json::from_str(&json).unwrap(); + assert_eq!(event.user_op_hash(), deserialized.user_op_hash()); + } + + #[test] + fn test_user_op_event_dropped_serialization() { + let event = UserOpEvent::Dropped { + user_op_hash: create_test_user_op_hash(), + reason: UserOpDropReason::Invalid("gas too low".to_string()), + }; + + let json = serde_json::to_string(&event).unwrap(); + assert!(json.contains("\"event\":\"Dropped\"")); + assert!(json.contains("gas too low")); + + let deserialized: UserOpEvent = serde_json::from_str(&json).unwrap(); + assert_eq!(event.user_op_hash(), deserialized.user_op_hash()); + } + + #[test] + fn test_user_op_event_included_serialization() { + let event = UserOpEvent::Included { + user_op_hash: create_test_user_op_hash(), + block_number: 12345, + tx_hash: b256!("3333333333333333333333333333333333333333333333333333333333333333"), + }; + + let json = serde_json::to_string(&event).unwrap(); + assert!(json.contains("\"event\":\"Included\"")); + assert!(json.contains("\"block_number\":12345")); + + let deserialized: UserOpEvent = serde_json::from_str(&json).unwrap(); + assert_eq!(event.user_op_hash(), deserialized.user_op_hash()); + } + + #[test] + fn test_user_op_hash_accessor() { + let hash = create_test_user_op_hash(); + + let added = UserOpEvent::AddedToMempool { + user_op_hash: hash, + sender: address!("2222222222222222222222222222222222222222"), + entry_point: address!("0000000071727De22E5E9d8BAf0edAc6f37da032"), + nonce: U256::from(1), + }; + assert_eq!(added.user_op_hash(), hash); + + let dropped = + UserOpEvent::Dropped { user_op_hash: hash, reason: UserOpDropReason::Expired }; + assert_eq!(dropped.user_op_hash(), hash); + + let included = UserOpEvent::Included { + user_op_hash: hash, + block_number: 100, + tx_hash: b256!("4444444444444444444444444444444444444444444444444444444444444444"), + }; + assert_eq!(included.user_op_hash(), hash); + } + + #[test] + fn test_generate_event_key_included() { + let user_op_hash = + b256!("1111111111111111111111111111111111111111111111111111111111111111"); + let tx_hash = b256!("2222222222222222222222222222222222222222222222222222222222222222"); + + let event = UserOpEvent::Included { user_op_hash, block_number: 100, tx_hash }; + + let key = event.generate_event_key(); + assert!(key.contains(&format!("{user_op_hash}"))); + assert!(key.contains(&format!("{tx_hash}"))); + } + + #[test] + fn test_user_op_drop_reason_variants() { + let invalid = UserOpDropReason::Invalid("test reason".to_string()); + let json = serde_json::to_string(&invalid).unwrap(); + assert!(json.contains("Invalid")); + assert!(json.contains("test reason")); + + let expired = UserOpDropReason::Expired; + let json = serde_json::to_string(&expired).unwrap(); + assert!(json.contains("Expired")); + + let replaced = UserOpDropReason::ReplacedByHigherFee; + let json = serde_json::to_string(&replaced).unwrap(); + assert!(json.contains("ReplacedByHigherFee")); + } +} diff --git a/crates/audit/tests/common/mod.rs b/crates/audit/tests/common/mod.rs new file mode 100644 index 0000000..095689c --- /dev/null +++ b/crates/audit/tests/common/mod.rs @@ -0,0 +1,75 @@ +use audit::test_utils::create_bundle_from_txn_data; +use base_bundles::BundleExtensions; +use rdkafka::{ClientConfig, consumer::StreamConsumer, producer::FutureProducer}; +use testcontainers::runners::AsyncRunner; +use testcontainers_modules::{kafka, kafka::Kafka, minio::MinIO}; +use uuid::Uuid; + +pub(crate) struct TestHarness { + pub s3_client: aws_sdk_s3::Client, + pub bucket_name: String, + #[allow(dead_code)] // TODO is read + pub kafka_producer: FutureProducer, + #[allow(dead_code)] // TODO is read + pub kafka_consumer: StreamConsumer, + _minio_container: testcontainers::ContainerAsync, + _kafka_container: testcontainers::ContainerAsync, +} + +impl TestHarness { + pub(crate) async fn new() -> Result> { + let minio_container = MinIO::default().start().await?; + let s3_port = minio_container.get_host_port_ipv4(9000).await?; + let s3_endpoint = format!("http://127.0.0.1:{s3_port}"); + + let config = aws_config::defaults(aws_config::BehaviorVersion::latest()) + .region("us-east-1") + .endpoint_url(&s3_endpoint) + .credentials_provider(aws_sdk_s3::config::Credentials::new( + "minioadmin", + "minioadmin", + None, + None, + "test", + )) + .load() + .await; + + let s3_client = aws_sdk_s3::Client::new(&config); + let bundle = create_bundle_from_txn_data(); + let bucket_name = format!( + "test-bucket-{}", + Uuid::new_v5(&Uuid::NAMESPACE_OID, bundle.bundle_hash().as_slice()) + ); + + s3_client.create_bucket().bucket(&bucket_name).send().await?; + + let kafka_container = Kafka::default().start().await?; + let bootstrap_servers = + format!("127.0.0.1:{}", kafka_container.get_host_port_ipv4(kafka::KAFKA_PORT).await?); + + let kafka_producer = ClientConfig::new() + .set("bootstrap.servers", &bootstrap_servers) + .set("message.timeout.ms", "5000") + .create::() + .expect("Failed to create Kafka FutureProducer"); + + let kafka_consumer = ClientConfig::new() + .set("group.id", "testcontainer-rs") + .set("bootstrap.servers", &bootstrap_servers) + .set("session.timeout.ms", "6000") + .set("enable.auto.commit", "false") + .set("auto.offset.reset", "earliest") + .create::() + .expect("Failed to create Kafka StreamConsumer"); + + Ok(Self { + s3_client, + bucket_name, + kafka_producer, + kafka_consumer, + _minio_container: minio_container, + _kafka_container: kafka_container, + }) + } +} diff --git a/crates/audit/tests/integration_tests.rs b/crates/audit/tests/integration_tests.rs new file mode 100644 index 0000000..90a1c4b --- /dev/null +++ b/crates/audit/tests/integration_tests.rs @@ -0,0 +1,117 @@ +#![allow(missing_docs)] + +use std::time::Duration; + +use alloy_primitives::{Address, B256, U256}; +use audit::{ + BundleEvent, BundleEventPublisher, BundleEventS3Reader, DropReason, KafkaAuditArchiver, + KafkaAuditLogReader, KafkaBundleEventPublisher, KafkaUserOpAuditLogReader, + KafkaUserOpEventPublisher, S3EventReaderWriter, UserOpEvent, UserOpEventPublisher, + UserOpEventReader, test_utils::create_bundle_from_txn_data, +}; +use base_bundles::BundleExtensions; +use uuid::Uuid; + +mod common; + +use common::TestHarness; + +#[tokio::test] +#[ignore = "TODO doesn't appear to work with minio, should test against a real S3 bucket"] +async fn test_kafka_publisher_s3_archiver_integration() +-> Result<(), Box> { + let harness = TestHarness::new().await?; + let topic = "test-mempool-events"; + + let s3_writer = + S3EventReaderWriter::new(harness.s3_client.clone(), harness.bucket_name.clone()); + + let bundle = create_bundle_from_txn_data(); + let test_bundle_id = Uuid::new_v5(&Uuid::NAMESPACE_OID, bundle.bundle_hash().as_slice()); + let test_events = [ + BundleEvent::Received { bundle_id: test_bundle_id, bundle: Box::new(bundle.clone()) }, + BundleEvent::Dropped { bundle_id: test_bundle_id, reason: DropReason::TimedOut }, + ]; + + let publisher = KafkaBundleEventPublisher::new(harness.kafka_producer, topic.to_string()); + + for event in &test_events { + publisher.publish(event.clone()).await?; + } + + let mut consumer = KafkaAuditArchiver::new( + KafkaAuditLogReader::new(harness.kafka_consumer, topic.to_string())?, + s3_writer.clone(), + 1, + 100, + false, + ); + + tokio::spawn(async move { + consumer.run().await.expect("error running consumer"); + }); + + // Wait for the messages to be received + let mut counter = 0; + loop { + counter += 1; + if counter > 10 { + panic!("unable to complete archiving within the deadline"); + } + + tokio::time::sleep(Duration::from_secs(1)).await; + let bundle_history = s3_writer.get_bundle_history(test_bundle_id).await?; + + if let Some(history) = bundle_history { + if history.history.len() != test_events.len() { + continue; + } + break; + } + continue; + } + + Ok(()) +} + +#[tokio::test] +async fn test_userop_kafka_publisher_reader_integration() +-> Result<(), Box> { + let harness = TestHarness::new().await?; + let topic = "test-userop-events"; + + let test_user_op_hash = B256::from_slice(&[1u8; 32]); + let test_sender = Address::from_slice(&[2u8; 20]); + let test_entry_point = Address::from_slice(&[3u8; 20]); + let test_nonce = U256::from(42); + + let test_event = UserOpEvent::AddedToMempool { + user_op_hash: test_user_op_hash, + sender: test_sender, + entry_point: test_entry_point, + nonce: test_nonce, + }; + + let publisher = KafkaUserOpEventPublisher::new(harness.kafka_producer, topic.to_string()); + publisher.publish(test_event.clone()).await?; + + let mut reader = KafkaUserOpAuditLogReader::new(harness.kafka_consumer, topic.to_string())?; + + let received = tokio::time::timeout(Duration::from_secs(10), reader.read_event()).await??; + + assert_eq!(received.event.user_op_hash(), test_user_op_hash); + + match received.event { + UserOpEvent::AddedToMempool { user_op_hash, sender, entry_point, nonce } => { + assert_eq!(user_op_hash, test_user_op_hash); + assert_eq!(sender, test_sender); + assert_eq!(entry_point, test_entry_point); + assert_eq!(nonce, test_nonce); + } + _ => panic!("Expected AddedToMempool event"), + } + + reader.commit().await?; + + Ok(()) +} diff --git a/crates/audit/tests/s3_test.rs b/crates/audit/tests/s3_test.rs new file mode 100644 index 0000000..6ffc979 --- /dev/null +++ b/crates/audit/tests/s3_test.rs @@ -0,0 +1,395 @@ +#![allow(missing_docs)] + +use std::sync::Arc; + +use alloy_primitives::{Address, B256, TxHash, U256}; +use audit::{ + BundleEvent, BundleEventS3Reader, Event, EventWriter, S3EventReaderWriter, UserOpDropReason, + UserOpEvent, UserOpEventS3Reader, UserOpEventWrapper, UserOpEventWriter, + test_utils::{TXN_HASH, create_bundle_from_txn_data}, +}; +use base_bundles::BundleExtensions; +use tokio::task::JoinSet; +use uuid::Uuid; + +mod common; +use common::TestHarness; + +fn create_test_event(key: &str, timestamp: i64, bundle_event: BundleEvent) -> Event { + Event { key: key.to_string(), timestamp, event: bundle_event } +} + +#[tokio::test] +async fn test_event_write_and_read() -> Result<(), Box> { + let harness = TestHarness::new().await?; + let writer = S3EventReaderWriter::new(harness.s3_client.clone(), harness.bucket_name.clone()); + + let bundle = create_bundle_from_txn_data(); + let bundle_id = Uuid::new_v5(&Uuid::NAMESPACE_OID, bundle.bundle_hash().as_slice()); + let event = create_test_event( + "test-key-1", + 1234567890, + BundleEvent::Received { bundle_id, bundle: Box::new(bundle.clone()) }, + ); + + writer.archive_event(event).await?; + + let bundle_history = writer.get_bundle_history(bundle_id).await?; + assert!(bundle_history.is_some()); + + let history = bundle_history.unwrap(); + assert_eq!(history.history.len(), 1); + assert_eq!(history.history[0].key(), "test-key-1"); + + let metadata = writer.get_transaction_metadata(TXN_HASH).await?; + assert!(metadata.is_some()); + + if let Some(metadata) = metadata { + assert!(metadata.bundle_ids.contains(&bundle_id)); + } + + let bundle_id_two = Uuid::new_v5(&Uuid::NAMESPACE_OID, bundle.bundle_hash().as_slice()); + let bundle = create_bundle_from_txn_data(); + let event = create_test_event( + "test-key-2", + 1234567890, + BundleEvent::Received { bundle_id: bundle_id_two, bundle: Box::new(bundle.clone()) }, + ); + + writer.archive_event(event).await?; + + let metadata = writer.get_transaction_metadata(TXN_HASH).await?; + assert!(metadata.is_some()); + + if let Some(metadata) = metadata { + assert!(metadata.bundle_ids.contains(&bundle_id)); + assert!(metadata.bundle_ids.contains(&bundle_id_two)); + } + + Ok(()) +} + +#[tokio::test] +async fn test_events_appended() -> Result<(), Box> { + let harness = TestHarness::new().await?; + let writer = S3EventReaderWriter::new(harness.s3_client.clone(), harness.bucket_name.clone()); + + let bundle = create_bundle_from_txn_data(); + let bundle_id = Uuid::new_v5(&Uuid::NAMESPACE_OID, bundle.bundle_hash().as_slice()); + + let events = [ + create_test_event( + "test-key-1", + 1234567890, + BundleEvent::Received { bundle_id, bundle: Box::new(bundle.clone()) }, + ), + create_test_event("test-key-2", 1234567891, BundleEvent::Cancelled { bundle_id }), + ]; + + for (idx, event) in events.iter().enumerate() { + writer.archive_event(event.clone()).await?; + + let bundle_history = writer.get_bundle_history(bundle_id).await?; + assert!(bundle_history.is_some()); + + let history = bundle_history.unwrap(); + assert_eq!(history.history.len(), idx + 1); + + let keys: Vec = history.history.iter().map(|e| e.key().to_string()).collect(); + assert_eq!( + keys, + events.iter().map(|e| e.key.clone()).take(idx + 1).collect::>() + ); + } + + Ok(()) +} + +#[tokio::test] +async fn test_event_deduplication() -> Result<(), Box> { + let harness = TestHarness::new().await?; + let writer = S3EventReaderWriter::new(harness.s3_client.clone(), harness.bucket_name.clone()); + + let bundle = create_bundle_from_txn_data(); + let bundle_id = Uuid::new_v5(&Uuid::NAMESPACE_OID, bundle.bundle_hash().as_slice()); + let bundle = create_bundle_from_txn_data(); + let event = create_test_event( + "duplicate-key", + 1234567890, + BundleEvent::Received { bundle_id, bundle: Box::new(bundle.clone()) }, + ); + + writer.archive_event(event.clone()).await?; + writer.archive_event(event).await?; + + let bundle_history = writer.get_bundle_history(bundle_id).await?; + assert!(bundle_history.is_some()); + + let history = bundle_history.unwrap(); + assert_eq!(history.history.len(), 1); + assert_eq!(history.history[0].key(), "duplicate-key"); + + Ok(()) +} + +#[tokio::test] +async fn test_nonexistent_data() -> Result<(), Box> { + let harness = TestHarness::new().await?; + let writer = S3EventReaderWriter::new(harness.s3_client.clone(), harness.bucket_name.clone()); + + let bundle = create_bundle_from_txn_data(); + let nonexistent_bundle_id = Uuid::new_v5(&Uuid::NAMESPACE_OID, bundle.bundle_hash().as_slice()); + let bundle_history = writer.get_bundle_history(nonexistent_bundle_id).await?; + assert!(bundle_history.is_none()); + + let nonexistent_tx_hash = TxHash::from([255u8; 32]); + let metadata = writer.get_transaction_metadata(nonexistent_tx_hash).await?; + assert!(metadata.is_none()); + + Ok(()) +} + +#[tokio::test] +#[ignore = "TODO doesn't appear to work with minio, should test against a real S3 bucket"] +async fn test_concurrent_writes_for_bundle() -> Result<(), Box> +{ + let harness = TestHarness::new().await?; + let writer = + Arc::new(S3EventReaderWriter::new(harness.s3_client.clone(), harness.bucket_name.clone())); + + let bundle = create_bundle_from_txn_data(); + let bundle_id = Uuid::new_v5(&Uuid::NAMESPACE_OID, bundle.bundle_hash().as_slice()); + + let event = create_test_event( + "hello-dan", + 1234567889i64, + BundleEvent::Received { bundle_id, bundle: Box::new(bundle.clone()) }, + ); + + writer.archive_event(event.clone()).await?; + + let mut join_set: JoinSet>> = + JoinSet::new(); + + for i in 0..4 { + let writer_clone = Arc::clone(&writer); + let key = if i % 4 == 0 { "shared-key".to_string() } else { format!("unique-key-{i}") }; + + let event = create_test_event( + &key, + 1234567890 + i as i64, + BundleEvent::Received { bundle_id, bundle: Box::new(bundle.clone()) }, + ); + + join_set.spawn(async move { + writer_clone.archive_event(event.clone()).await.map_err(|e| e.into()) + }); + } + + let tasks = join_set.join_all().await; + assert_eq!(tasks.len(), 4); + for t in &tasks { + assert!(t.is_ok()); + } + + let bundle_history = writer.get_bundle_history(bundle_id).await?; + assert!(bundle_history.is_some()); + + let history = bundle_history.unwrap(); + + let shared_count = history.history.iter().filter(|e| e.key() == "shared-key").count(); + assert_eq!(shared_count, 1); + + let unique_count = + history.history.iter().filter(|e| e.key().starts_with("unique-key-")).count(); + assert_eq!(unique_count, 3); + + assert_eq!(history.history.len(), 4); + + Ok(()) +} + +fn create_test_userop_event( + key: &str, + timestamp: i64, + userop_event: UserOpEvent, +) -> UserOpEventWrapper { + UserOpEventWrapper { key: key.to_string(), timestamp, event: userop_event } +} + +#[tokio::test] +async fn test_userop_event_write_and_read() -> Result<(), Box> +{ + let harness = TestHarness::new().await?; + let writer = S3EventReaderWriter::new(harness.s3_client.clone(), harness.bucket_name.clone()); + + let user_op_hash = B256::from([1u8; 32]); + let sender = Address::from([2u8; 20]); + let entry_point = Address::from([3u8; 20]); + let nonce = U256::from(1); + + let event = create_test_userop_event( + "test-userop-key-1", + 1234567890, + UserOpEvent::AddedToMempool { user_op_hash, sender, entry_point, nonce }, + ); + + writer.archive_userop_event(event).await?; + + let userop_history = writer.get_userop_history(user_op_hash).await?; + assert!(userop_history.is_some()); + + let history = userop_history.unwrap(); + assert_eq!(history.history.len(), 1); + assert_eq!(history.history[0].key(), "test-userop-key-1"); + + Ok(()) +} + +#[tokio::test] +async fn test_userop_events_appended() -> Result<(), Box> { + let harness = TestHarness::new().await?; + let writer = S3EventReaderWriter::new(harness.s3_client.clone(), harness.bucket_name.clone()); + + let user_op_hash = B256::from([10u8; 32]); + let sender = Address::from([11u8; 20]); + let entry_point = Address::from([12u8; 20]); + let nonce = U256::from(1); + let tx_hash = TxHash::from([13u8; 32]); + + let events = [ + create_test_userop_event( + "userop-key-1", + 1234567890, + UserOpEvent::AddedToMempool { user_op_hash, sender, entry_point, nonce }, + ), + create_test_userop_event( + "userop-key-2", + 1234567891, + UserOpEvent::Included { user_op_hash, block_number: 12345, tx_hash }, + ), + ]; + + for (idx, event) in events.iter().enumerate() { + writer.archive_userop_event(event.clone()).await?; + + let userop_history = writer.get_userop_history(user_op_hash).await?; + assert!(userop_history.is_some()); + + let history = userop_history.unwrap(); + assert_eq!(history.history.len(), idx + 1); + + let keys: Vec = history.history.iter().map(|e| e.key().to_string()).collect(); + assert_eq!( + keys, + events.iter().map(|e| e.key.clone()).take(idx + 1).collect::>() + ); + } + + Ok(()) +} + +#[tokio::test] +async fn test_userop_event_deduplication() -> Result<(), Box> { + let harness = TestHarness::new().await?; + let writer = S3EventReaderWriter::new(harness.s3_client.clone(), harness.bucket_name.clone()); + + let user_op_hash = B256::from([20u8; 32]); + let sender = Address::from([21u8; 20]); + let entry_point = Address::from([22u8; 20]); + let nonce = U256::from(1); + + let event = create_test_userop_event( + "duplicate-userop-key", + 1234567890, + UserOpEvent::AddedToMempool { user_op_hash, sender, entry_point, nonce }, + ); + + writer.archive_userop_event(event.clone()).await?; + writer.archive_userop_event(event).await?; + + let userop_history = writer.get_userop_history(user_op_hash).await?; + assert!(userop_history.is_some()); + + let history = userop_history.unwrap(); + assert_eq!(history.history.len(), 1); + assert_eq!(history.history[0].key(), "duplicate-userop-key"); + + Ok(()) +} + +#[tokio::test] +async fn test_userop_nonexistent_returns_none() +-> Result<(), Box> { + let harness = TestHarness::new().await?; + let writer = S3EventReaderWriter::new(harness.s3_client.clone(), harness.bucket_name.clone()); + + let nonexistent_hash = B256::from([255u8; 32]); + let userop_history = writer.get_userop_history(nonexistent_hash).await?; + assert!(userop_history.is_none()); + + Ok(()) +} + +#[tokio::test] +async fn test_userop_all_event_types() -> Result<(), Box> { + let harness = TestHarness::new().await?; + let writer = S3EventReaderWriter::new(harness.s3_client.clone(), harness.bucket_name.clone()); + + let user_op_hash = B256::from([30u8; 32]); + let sender = Address::from([31u8; 20]); + let entry_point = Address::from([32u8; 20]); + let nonce = U256::from(1); + let tx_hash = TxHash::from([33u8; 32]); + + let event1 = create_test_userop_event( + "event-added", + 1234567890, + UserOpEvent::AddedToMempool { user_op_hash, sender, entry_point, nonce }, + ); + writer.archive_userop_event(event1).await?; + + let event2 = create_test_userop_event( + "event-included", + 1234567891, + UserOpEvent::Included { user_op_hash, block_number: 12345, tx_hash }, + ); + writer.archive_userop_event(event2).await?; + + let userop_history = writer.get_userop_history(user_op_hash).await?; + assert!(userop_history.is_some()); + + let history = userop_history.unwrap(); + assert_eq!(history.history.len(), 2); + assert_eq!(history.history[0].key(), "event-added"); + assert_eq!(history.history[1].key(), "event-included"); + + Ok(()) +} + +#[tokio::test] +async fn test_userop_dropped_event() -> Result<(), Box> { + let harness = TestHarness::new().await?; + let writer = S3EventReaderWriter::new(harness.s3_client.clone(), harness.bucket_name.clone()); + + let user_op_hash = B256::from([40u8; 32]); + + let event = create_test_userop_event( + "event-dropped", + 1234567890, + UserOpEvent::Dropped { + user_op_hash, + reason: UserOpDropReason::Invalid("AA21 didn't pay prefund".to_string()), + }, + ); + writer.archive_userop_event(event).await?; + + let userop_history = writer.get_userop_history(user_op_hash).await?; + assert!(userop_history.is_some()); + + let history = userop_history.unwrap(); + assert_eq!(history.history.len(), 1); + assert_eq!(history.history[0].key(), "event-dropped"); + + Ok(()) +} diff --git a/crates/basectl/Cargo.toml b/crates/basectl/Cargo.toml index 3064f76..f12ca94 100644 --- a/crates/basectl/Cargo.toml +++ b/crates/basectl/Cargo.toml @@ -24,7 +24,7 @@ alloy-rpc-types-eth = { workspace = true } alloy-eips = { workspace = true } op-alloy-network = { workspace = true } op-alloy-consensus = { workspace = true } -base-flashtypes = { workspace = true } +base-primitives = { workspace = true } url = { workspace = true } alloy-primitives = { workspace = true } alloy-sol-types = { workspace = true } diff --git a/crates/basectl/src/app/resources.rs b/crates/basectl/src/app/resources.rs index ac74277..55696a1 100644 --- a/crates/basectl/src/app/resources.rs +++ b/crates/basectl/src/app/resources.rs @@ -1,6 +1,6 @@ use std::collections::VecDeque; -use base_flashtypes::Flashblock; +use base_primitives::flashblocks::Flashblock; use tokio::sync::mpsc; use crate::{ diff --git a/crates/basectl/src/app/runner.rs b/crates/basectl/src/app/runner.rs index a596675..07a6359 100644 --- a/crates/basectl/src/app/runner.rs +++ b/crates/basectl/src/app/runner.rs @@ -1,5 +1,5 @@ use anyhow::Result; -use base_flashtypes::Flashblock; +use base_primitives::flashblocks::Flashblock; use tokio::sync::mpsc; use super::{App, Resources, ViewId, views::create_view}; diff --git a/crates/basectl/src/rpc.rs b/crates/basectl/src/rpc.rs index 2957a4d..41c4713 100644 --- a/crates/basectl/src/rpc.rs +++ b/crates/basectl/src/rpc.rs @@ -5,7 +5,7 @@ use alloy_primitives::{Address, B256}; use alloy_provider::{Provider, ProviderBuilder}; use alloy_rpc_types_eth::{BlockNumberOrTag, TransactionTrait}; use anyhow::Result; -use base_flashtypes::Flashblock; +use base_primitives::flashblocks::Flashblock; use futures_util::{StreamExt, stream}; use op_alloy_network::Optimism; use tokio::sync::mpsc; diff --git a/crates/ingress-rpc/Cargo.toml b/crates/ingress-rpc/Cargo.toml new file mode 100644 index 0000000..5d4a62a --- /dev/null +++ b/crates/ingress-rpc/Cargo.toml @@ -0,0 +1,41 @@ +[package] +name = "ingress-rpc" +version.workspace = true +rust-version.workspace = true +license.workspace = true +homepage.workspace = true +repository.workspace = true +edition.workspace = true + +[dependencies] +url.workspace = true +utils.workspace = true +op-revm.workspace = true +metrics.workspace = true +audit.workspace = true +async-trait.workspace = true +metrics-derive.workspace = true +op-alloy-network.workspace = true +alloy-signer-local.workspace = true +base-reth-rpc-types.workspace = true +alloy-primitives = { workspace = true, features = ["map-foldhash", "serde"] } +tokio = { workspace = true, features = ["full"] } +tracing = { workspace = true, features = ["std"] } +anyhow = { workspace = true, features = ["std"] } +serde_json = { workspace = true, features = ["std"] } +rdkafka = { workspace = true, features = ["tokio", "libz", "zstd", "ssl-vendored"] } +alloy-consensus = { workspace = true, features = ["std"] } +alloy-provider = { workspace = true, features = ["reqwest"] } +jsonrpsee = { workspace = true, features = ["server", "macros"] } +backon = { workspace = true, features = ["std", "tokio-sleep"] } +axum = { workspace = true, features = ["tokio", "http1", "json"] } +clap = { version = "4.5.47", features = ["std", "derive", "env"] } +op-alloy-consensus = { workspace = true, features = ["std", "k256", "serde"] } +moka = { workspace = true, features = ["future"] } +uuid = { workspace = true, features = ["v5"] } +base-bundles = { workspace = true } + +[dev-dependencies] +mockall = "0.13" +wiremock.workspace = true +jsonrpsee = { workspace = true, features = ["server", "http-client", "macros"] } diff --git a/crates/ingress-rpc/src/health.rs b/crates/ingress-rpc/src/health.rs new file mode 100644 index 0000000..718104e --- /dev/null +++ b/crates/ingress-rpc/src/health.rs @@ -0,0 +1,32 @@ +use std::net::SocketAddr; + +use axum::{Router, http::StatusCode, response::IntoResponse, routing::get}; +use tracing::info; + +/// Health check handler that always returns 200 OK +async fn health() -> impl IntoResponse { + StatusCode::OK +} + +/// Bind and start the health check server on the specified address. +/// Returns a handle that can be awaited to run the server. +pub async fn bind_health_server( + addr: SocketAddr, +) -> anyhow::Result<(SocketAddr, tokio::task::JoinHandle>)> { + let app = Router::new().route("/health", get(health)); + + let listener = tokio::net::TcpListener::bind(addr).await?; + let bound_addr = listener.local_addr()?; + + info!( + message = "Health check server bound successfully", + address = %bound_addr + ); + + let handle = tokio::spawn(async move { + axum::serve(listener, app).await?; + Ok(()) + }); + + Ok((bound_addr, handle)) +} diff --git a/crates/ingress-rpc/src/lib.rs b/crates/ingress-rpc/src/lib.rs new file mode 100644 index 0000000..13a1fb7 --- /dev/null +++ b/crates/ingress-rpc/src/lib.rs @@ -0,0 +1,199 @@ +pub mod health; +pub mod metrics; +pub mod queue; +pub mod service; +pub mod validation; +use std::{ + net::{IpAddr, SocketAddr}, + str::FromStr, +}; + +use alloy_primitives::TxHash; +use alloy_provider::{Provider, ProviderBuilder, RootProvider}; +use base_bundles::{AcceptedBundle, MeterBundleResponse}; +use clap::Parser; +use op_alloy_network::Optimism; +use tokio::sync::broadcast; +use tracing::{error, warn}; +use url::Url; + +#[derive(Debug, Clone, Copy)] +pub enum TxSubmissionMethod { + Mempool, + Kafka, + MempoolAndKafka, + None, +} + +impl FromStr for TxSubmissionMethod { + type Err = String; + + fn from_str(s: &str) -> Result { + match s { + "mempool" => Ok(TxSubmissionMethod::Mempool), + "kafka" => Ok(TxSubmissionMethod::Kafka), + "mempool,kafka" | "kafka,mempool" => Ok(TxSubmissionMethod::MempoolAndKafka), + "none" => Ok(TxSubmissionMethod::None), + _ => Err(format!( + "Invalid submission method: '{s}'. Valid options: mempool, kafka, mempool,kafka, kafka,mempool, none" + )), + } + } +} + +#[derive(Parser, Debug, Clone)] +#[command(author, version, about, long_about = None)] +pub struct Config { + /// Address to bind the RPC server to + #[arg(long, env = "TIPS_INGRESS_ADDRESS", default_value = "0.0.0.0")] + pub address: IpAddr, + + /// Port to bind the RPC server to + #[arg(long, env = "TIPS_INGRESS_PORT", default_value = "8080")] + pub port: u16, + + /// URL of the mempool service to proxy transactions to + #[arg(long, env = "TIPS_INGRESS_RPC_MEMPOOL")] + pub mempool_url: Url, + + /// Method to submit transactions to the mempool + #[arg(long, env = "TIPS_INGRESS_TX_SUBMISSION_METHOD", default_value = "mempool")] + pub tx_submission_method: TxSubmissionMethod, + + /// Kafka brokers for publishing mempool events + #[arg(long, env = "TIPS_INGRESS_KAFKA_INGRESS_PROPERTIES_FILE")] + pub ingress_kafka_properties: String, + + /// Kafka topic for queuing transactions before the DB Writer + #[arg(long, env = "TIPS_INGRESS_KAFKA_INGRESS_TOPIC", default_value = "tips-ingress")] + pub ingress_topic: String, + + /// Kafka properties file for audit events + #[arg(long, env = "TIPS_INGRESS_KAFKA_AUDIT_PROPERTIES_FILE")] + pub audit_kafka_properties: String, + + /// Kafka topic for audit events + #[arg(long, env = "TIPS_INGRESS_KAFKA_AUDIT_TOPIC", default_value = "tips-audit")] + pub audit_topic: String, + + #[arg(long, env = "TIPS_INGRESS_LOG_LEVEL", default_value = "info")] + pub log_level: String, + + #[arg(long, env = "TIPS_INGRESS_LOG_FORMAT", default_value = "pretty")] + pub log_format: utils::logger::LogFormat, + + /// Default lifetime for sent transactions in seconds (default: 3 hours) + #[arg( + long, + env = "TIPS_INGRESS_SEND_TRANSACTION_DEFAULT_LIFETIME_SECONDS", + default_value = "10800" + )] + pub send_transaction_default_lifetime_seconds: u64, + + /// URL of the simulation RPC service for bundle metering + #[arg(long, env = "TIPS_INGRESS_RPC_SIMULATION")] + pub simulation_rpc: Url, + + /// Port to bind the Prometheus metrics server to + #[arg(long, env = "TIPS_INGRESS_METRICS_ADDR", default_value = "0.0.0.0:9002")] + pub metrics_addr: SocketAddr, + + /// Configurable block time in milliseconds (default: 2000 milliseconds) + #[arg(long, env = "TIPS_INGRESS_BLOCK_TIME_MILLISECONDS", default_value = "2000")] + pub block_time_milliseconds: u64, + + /// Timeout for bundle metering in milliseconds (default: 2000 milliseconds) + #[arg(long, env = "TIPS_INGRESS_METER_BUNDLE_TIMEOUT_MS", default_value = "2000")] + pub meter_bundle_timeout_ms: u64, + + /// URLs of the builder RPC service for setting metering information + #[arg(long, env = "TIPS_INGRESS_BUILDER_RPCS", value_delimiter = ',')] + pub builder_rpcs: Vec, + + /// Maximum number of `MeterBundleResponse`s to buffer in memory + #[arg(long, env = "TIPS_INGRESS_MAX_BUFFERED_METER_BUNDLE_RESPONSES", default_value = "100")] + pub max_buffered_meter_bundle_responses: usize, + + /// Maximum number of backrun bundles to buffer in memory + #[arg(long, env = "TIPS_INGRESS_MAX_BUFFERED_BACKRUN_BUNDLES", default_value = "100")] + pub max_buffered_backrun_bundles: usize, + + /// Address to bind the health check server to + #[arg(long, env = "TIPS_INGRESS_HEALTH_CHECK_ADDR", default_value = "0.0.0.0:8081")] + pub health_check_addr: SocketAddr, + + /// chain id + #[arg(long, env = "TIPS_INGRESS_CHAIN_ID", default_value = "11")] + pub chain_id: u64, + + /// Enable backrun bundle submission to op-rbuilder + #[arg(long, env = "TIPS_INGRESS_BACKRUN_ENABLED", default_value = "false")] + pub backrun_enabled: bool, + + /// Maximum number of transactions allowed in a backrun bundle (including target tx) + #[arg(long, env = "MAX_BACKRUN_TXS", default_value = "5")] + pub max_backrun_txs: usize, + + /// Maximum total gas limit for all transactions in a backrun bundle + #[arg(long, env = "MAX_BACKRUN_GAS_LIMIT", default_value = "5000000")] + pub max_backrun_gas_limit: u64, + + /// URL of third-party RPC endpoint to forward raw transactions to (enables forwarding if set) + #[arg(long, env = "TIPS_INGRESS_RAW_TX_FORWARD_RPC")] + pub raw_tx_forward_rpc: Option, + + /// TTL for bundle cache in seconds + #[arg(long, env = "TIPS_INGRESS_BUNDLE_CACHE_TTL", default_value = "20")] + pub bundle_cache_ttl: u64, + + /// Enable sending to builder + #[arg(long, env = "TIPS_INGRESS_SEND_TO_BUILDER", default_value = "false")] + pub send_to_builder: bool, +} + +pub fn connect_ingress_to_builder( + metering_rx: broadcast::Receiver, + backrun_rx: broadcast::Receiver, + builder_rpc: Url, +) { + let builder: RootProvider = ProviderBuilder::new() + .disable_recommended_fillers() + .network::() + .connect_http(builder_rpc); + + let metering_builder = builder.clone(); + tokio::spawn(async move { + let mut event_rx = metering_rx; + while let Ok(event) = event_rx.recv().await { + if event.results.is_empty() { + warn!(message = "received metering information with no transactions", hash=%event.bundle_hash); + continue; + } + + let tx_hash = event.results[0].tx_hash; + if let Err(e) = metering_builder + .client() + .request::<(TxHash, MeterBundleResponse), ()>( + "base_setMeteringInformation", + (tx_hash, event), + ) + .await + { + error!(error = %e, "Failed to set metering information for tx hash: {tx_hash}"); + } + } + }); + + tokio::spawn(async move { + let mut event_rx = backrun_rx; + while let Ok(accepted_bundle) = event_rx.recv().await { + if let Err(e) = builder + .client() + .request::<(AcceptedBundle,), ()>("base_sendBackrunBundle", (accepted_bundle,)) + .await + { + error!(error = ?e, "Failed to send backrun bundle to builder"); + } + } + }); +} diff --git a/crates/ingress-rpc/src/metrics.rs b/crates/ingress-rpc/src/metrics.rs new file mode 100644 index 0000000..a62b3b8 --- /dev/null +++ b/crates/ingress-rpc/src/metrics.rs @@ -0,0 +1,54 @@ +use metrics::{Counter, Histogram}; +use metrics_derive::Metrics; +use tokio::time::Duration; + +pub fn record_histogram(rpc_latency: Duration, rpc: String) { + metrics::histogram!("tips_ingress_rpc_rpc_latency", "rpc" => rpc) + .record(rpc_latency.as_secs_f64()); +} + +#[derive(Metrics, Clone)] +#[metrics(scope = "tips_ingress_rpc")] +pub struct Metrics { + #[metric(describe = "Number of valid transactions received")] + pub transactions_received: Counter, + + #[metric(describe = "Number of valid bundles parsed")] + pub bundles_parsed: Counter, + + #[metric(describe = "Number of bundles simulated")] + pub successful_simulations: Counter, + + #[metric(describe = "Number of bundles simulated")] + pub failed_simulations: Counter, + + #[metric(describe = "Number of bundles sent to kafka")] + pub sent_to_kafka: Counter, + + #[metric(describe = "Number of transactions sent to mempool")] + pub sent_to_mempool: Counter, + + #[metric(describe = "Duration of validate_tx")] + pub validate_tx_duration: Histogram, + + #[metric(describe = "Duration of validate_bundle")] + pub validate_bundle_duration: Histogram, + + #[metric(describe = "Duration of meter_bundle")] + pub meter_bundle_duration: Histogram, + + #[metric(describe = "Duration of send_raw_transaction")] + pub send_raw_transaction_duration: Histogram, + + #[metric(describe = "Total backrun bundles received")] + pub backrun_bundles_received_total: Counter, + + #[metric(describe = "Duration to send backrun bundle to op-rbuilder")] + pub backrun_bundles_sent_duration: Histogram, + + #[metric(describe = "Total raw transactions forwarded to additional endpoint")] + pub raw_tx_forwards_total: Counter, + + #[metric(describe = "Number of bundles that exceeded the metering time")] + pub bundles_exceeded_metering_time: Counter, +} diff --git a/crates/ingress-rpc/src/queue.rs b/crates/ingress-rpc/src/queue.rs new file mode 100644 index 0000000..a695eaa --- /dev/null +++ b/crates/ingress-rpc/src/queue.rs @@ -0,0 +1,129 @@ +use std::sync::Arc; + +use alloy_primitives::B256; +use anyhow::Result; +use async_trait::async_trait; +use backon::{ExponentialBuilder, Retryable}; +use base_bundles::AcceptedBundle; +use rdkafka::producer::{FutureProducer, FutureRecord}; +use tokio::time::Duration; +use tracing::{error, info}; + +#[async_trait] +pub trait MessageQueue: Send + Sync { + async fn publish(&self, topic: &str, key: &str, payload: &[u8]) -> Result<()>; +} + +pub struct KafkaMessageQueue { + producer: FutureProducer, +} + +impl KafkaMessageQueue { + pub fn new(producer: FutureProducer) -> Self { + Self { producer } + } +} + +#[async_trait] +impl MessageQueue for KafkaMessageQueue { + async fn publish(&self, topic: &str, key: &str, payload: &[u8]) -> Result<()> { + let enqueue = || async { + let record = FutureRecord::to(topic).key(key).payload(payload); + + match self.producer.send(record, Duration::from_secs(5)).await { + Ok((partition, offset)) => { + info!( + key = %key, + partition = partition, + offset = offset, + topic = %topic, + "Successfully enqueued message" + ); + Ok(()) + } + Err((err, _)) => { + error!( + key = key, + error = %err, + topic = topic, + "Failed to enqueue message" + ); + Err(anyhow::anyhow!("Failed to enqueue bundle: {err}")) + } + } + }; + + enqueue + .retry( + &ExponentialBuilder::default() + .with_min_delay(Duration::from_millis(100)) + .with_max_delay(Duration::from_secs(5)) + .with_max_times(3), + ) + .notify(|err: &anyhow::Error, dur: Duration| { + info!("retrying to enqueue message {:?} after {:?}", err, dur); + }) + .await + } +} + +pub struct BundleQueuePublisher { + queue: Arc, + topic: String, +} + +impl BundleQueuePublisher { + pub fn new(queue: Arc, topic: String) -> Self { + Self { queue, topic } + } + + pub async fn publish(&self, bundle: &AcceptedBundle, hash: &B256) -> Result<()> { + let key = hash.to_string(); + let payload = serde_json::to_vec(bundle)?; + self.queue.publish(&self.topic, &key, &payload).await + } +} + +#[cfg(test)] +mod tests { + use audit::test_utils::create_test_meter_bundle_response; + use base_bundles::{AcceptedBundle, Bundle, BundleExtensions}; + use rdkafka::config::ClientConfig; + use tokio::time::{Duration, Instant}; + + use super::*; + + fn create_test_bundle() -> Bundle { + Bundle::default() + } + + #[tokio::test] + async fn test_backoff_retry_logic() { + // use an invalid broker address to trigger the backoff logic + let producer = ClientConfig::new() + .set("bootstrap.servers", "localhost:9999") + .set("message.timeout.ms", "100") + .create() + .expect("Producer creation failed"); + + let publisher = KafkaMessageQueue::new(producer); + let bundle = create_test_bundle(); + let accepted_bundle = + AcceptedBundle::new(bundle.try_into().unwrap(), create_test_meter_bundle_response()); + let bundle_hash = &accepted_bundle.bundle_hash(); + + let start = Instant::now(); + let result = publisher + .publish( + "tips-ingress-rpc", + bundle_hash.to_string().as_str(), + &serde_json::to_vec(&accepted_bundle).unwrap(), + ) + .await; + let elapsed = start.elapsed(); + + // the backoff tries at minimum 100ms, so verify we tried at least once + assert!(result.is_err()); + assert!(elapsed >= Duration::from_millis(100)); + } +} diff --git a/crates/ingress-rpc/src/service.rs b/crates/ingress-rpc/src/service.rs new file mode 100644 index 0000000..0809cbd --- /dev/null +++ b/crates/ingress-rpc/src/service.rs @@ -0,0 +1,709 @@ +use std::{ + sync::Arc, + time::{SystemTime, UNIX_EPOCH}, +}; + +use alloy_consensus::{ + Transaction, + transaction::{Recovered, SignerRecoverable}, +}; +use alloy_primitives::{B256, Bytes}; +use alloy_provider::{Provider, RootProvider, network::eip2718::Decodable2718}; +use audit::BundleEvent; +use base_bundles::{ + AcceptedBundle, Bundle, BundleExtensions, BundleHash, CancelBundle, MeterBundleResponse, + ParsedBundle, +}; +use base_reth_rpc_types::EthApiError; +use jsonrpsee::{ + core::{RpcResult, async_trait}, + proc_macros::rpc, +}; +use moka::future::Cache; +use op_alloy_consensus::OpTxEnvelope; +use op_alloy_network::Optimism; +use tokio::{ + sync::{broadcast, mpsc}, + time::{Duration, Instant, timeout}, +}; +use tracing::{debug, info, warn}; + +use crate::{ + Config, TxSubmissionMethod, + metrics::{Metrics, record_histogram}, + queue::{BundleQueuePublisher, MessageQueue}, + validation::validate_bundle, +}; + +/// RPC providers for different endpoints +pub struct Providers { + pub mempool: RootProvider, + pub simulation: RootProvider, + pub raw_tx_forward: Option>, +} + +#[rpc(server, namespace = "eth")] +pub trait IngressApi { + /// `eth_sendBundle` can be used to send your bundles to the builder. + #[method(name = "sendBundle")] + async fn send_bundle(&self, bundle: Bundle) -> RpcResult; + + #[method(name = "sendBackrunBundle")] + async fn send_backrun_bundle(&self, bundle: Bundle) -> RpcResult; + + /// `eth_cancelBundle` is used to prevent a submitted bundle from being included on-chain. + #[method(name = "cancelBundle")] + async fn cancel_bundle(&self, request: CancelBundle) -> RpcResult<()>; + + /// Handler for: `eth_sendRawTransaction` + #[method(name = "sendRawTransaction")] + async fn send_raw_transaction(&self, tx: Bytes) -> RpcResult; +} + +pub struct IngressService { + mempool_provider: Arc>, + simulation_provider: Arc>, + raw_tx_forward_provider: Option>>, + tx_submission_method: TxSubmissionMethod, + bundle_queue_publisher: BundleQueuePublisher, + audit_channel: mpsc::UnboundedSender, + send_transaction_default_lifetime_seconds: u64, + metrics: Metrics, + block_time_milliseconds: u64, + meter_bundle_timeout_ms: u64, + builder_tx: broadcast::Sender, + backrun_enabled: bool, + builder_backrun_tx: broadcast::Sender, + max_backrun_txs: usize, + max_backrun_gas_limit: u64, + bundle_cache: Cache, + send_to_builder: bool, +} + +impl IngressService { + pub fn new( + providers: Providers, + queue: Q, + audit_channel: mpsc::UnboundedSender, + builder_tx: broadcast::Sender, + builder_backrun_tx: broadcast::Sender, + config: Config, + ) -> Self { + let mempool_provider = Arc::new(providers.mempool); + let simulation_provider = Arc::new(providers.simulation); + let raw_tx_forward_provider = providers.raw_tx_forward.map(Arc::new); + let queue_connection = Arc::new(queue); + + // A TTL cache to deduplicate bundles with the same Bundle ID + let bundle_cache = + Cache::builder().time_to_live(Duration::from_secs(config.bundle_cache_ttl)).build(); + Self { + mempool_provider, + simulation_provider, + raw_tx_forward_provider, + tx_submission_method: config.tx_submission_method, + bundle_queue_publisher: BundleQueuePublisher::new( + queue_connection.clone(), + config.ingress_topic, + ), + audit_channel, + send_transaction_default_lifetime_seconds: config + .send_transaction_default_lifetime_seconds, + metrics: Metrics::default(), + block_time_milliseconds: config.block_time_milliseconds, + meter_bundle_timeout_ms: config.meter_bundle_timeout_ms, + builder_tx, + backrun_enabled: config.backrun_enabled, + builder_backrun_tx, + max_backrun_txs: config.max_backrun_txs, + max_backrun_gas_limit: config.max_backrun_gas_limit, + bundle_cache, + send_to_builder: config.send_to_builder, + } + } +} + +fn validate_backrun_bundle_limits( + txs_count: usize, + total_gas_limit: u64, + max_backrun_txs: usize, + max_backrun_gas_limit: u64, +) -> Result<(), String> { + if txs_count < 2 { + return Err( + "Backrun bundle must have at least 2 transactions (target + backrun)".to_string() + ); + } + if txs_count > max_backrun_txs { + return Err(format!( + "Backrun bundle exceeds max transaction count: {txs_count} > {max_backrun_txs}", + )); + } + if total_gas_limit > max_backrun_gas_limit { + return Err(format!( + "Backrun bundle exceeds max gas limit: {total_gas_limit} > {max_backrun_gas_limit}", + )); + } + Ok(()) +} + +#[async_trait] +impl IngressApiServer for IngressService { + async fn send_backrun_bundle(&self, bundle: Bundle) -> RpcResult { + if !self.backrun_enabled { + return Err(EthApiError::InvalidParams("Backrun bundle submission is disabled".into()) + .into_rpc_err()); + } + + let start = Instant::now(); + let (accepted_bundle, bundle_hash) = + self.validate_parse_and_meter_bundle(&bundle, false).await?; + + let total_gas_limit: u64 = accepted_bundle.txs.iter().map(|tx| tx.gas_limit()).sum(); + validate_backrun_bundle_limits( + accepted_bundle.txs.len(), + total_gas_limit, + self.max_backrun_txs, + self.max_backrun_gas_limit, + ) + .map_err(|e| EthApiError::InvalidParams(e).into_rpc_err())?; + + self.metrics.backrun_bundles_received_total.increment(1); + + self.builder_backrun_tx.send(accepted_bundle.clone()).map_err(|e| { + EthApiError::InvalidParams(format!("Failed to send backrun bundle: {e}")).into_rpc_err() + })?; + + self.send_audit_event(&accepted_bundle, bundle_hash); + + self.metrics.backrun_bundles_sent_duration.record(start.elapsed().as_secs_f64()); + + Ok(BundleHash { bundle_hash }) + } + + async fn send_bundle(&self, bundle: Bundle) -> RpcResult { + let (accepted_bundle, bundle_hash) = + self.validate_parse_and_meter_bundle(&bundle, true).await?; + + // Get meter_bundle_response for builder broadcast + let meter_bundle_response = accepted_bundle.meter_bundle_response.clone(); + + // asynchronously send the meter bundle response to the builder + self.builder_tx + .send(meter_bundle_response) + .map_err(|e| EthApiError::InvalidParams(e.to_string()).into_rpc_err())?; + + // publish the bundle to the queue + if let Err(e) = self.bundle_queue_publisher.publish(&accepted_bundle, &bundle_hash).await { + warn!(message = "Failed to publish bundle to queue", bundle_hash = %bundle_hash, error = %e); + return Err(EthApiError::InvalidParams("Failed to queue bundle".into()).into_rpc_err()); + } + + info!( + message = "queued bundle", + bundle_hash = %bundle_hash, + ); + + // asynchronously send the audit event to the audit channel + self.send_audit_event(&accepted_bundle, bundle_hash); + + Ok(BundleHash { bundle_hash }) + } + + async fn cancel_bundle(&self, _request: CancelBundle) -> RpcResult<()> { + warn!(message = "TODO: implement cancel_bundle", method = "cancel_bundle"); + todo!("implement cancel_bundle") + } + + async fn send_raw_transaction(&self, data: Bytes) -> RpcResult { + let start = Instant::now(); + let transaction = self.get_tx(&data).await?; + + self.metrics.transactions_received.increment(1); + + let send_to_kafka = matches!( + self.tx_submission_method, + TxSubmissionMethod::Kafka | TxSubmissionMethod::MempoolAndKafka + ); + let send_to_mempool = matches!( + self.tx_submission_method, + TxSubmissionMethod::Mempool | TxSubmissionMethod::MempoolAndKafka + ); + + // Forward before metering + if let Some(forward_provider) = self.raw_tx_forward_provider.clone() { + self.metrics.raw_tx_forwards_total.increment(1); + let tx_data = data.clone(); + let tx_hash = transaction.tx_hash(); + tokio::spawn(async move { + match forward_provider.send_raw_transaction(tx_data.iter().as_slice()).await { + Ok(_) => { + debug!(message = "Forwarded raw tx", hash = %tx_hash); + } + Err(e) => { + warn!(message = "Failed to forward raw tx", hash = %tx_hash, error = %e); + } + } + }); + } + + let expiry_timestamp = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs() + + self.send_transaction_default_lifetime_seconds; + + let bundle = Bundle { + txs: vec![data.clone()], + max_timestamp: Some(expiry_timestamp), + reverting_tx_hashes: vec![transaction.tx_hash()], + ..Default::default() + }; + + let parsed_bundle: ParsedBundle = bundle + .clone() + .try_into() + .map_err(|e: String| EthApiError::InvalidParams(e).into_rpc_err())?; + + let bundle_hash = &parsed_bundle.bundle_hash(); + + if self.bundle_cache.get(bundle_hash).await.is_some() { + debug!( + message = "Duplicate bundle detected, skipping Kafka publish", + bundle_hash = %bundle_hash, + transaction_hash = %transaction.tx_hash(), + ); + } else { + self.bundle_cache.insert(*bundle_hash, ()).await; + self.metrics.bundles_parsed.increment(1); + + let meter_bundle_response = match self.meter_bundle(&bundle, bundle_hash).await { + Ok(response) => { + info!(message = "Metering succeeded for raw transaction", bundle_hash = %bundle_hash, response = ?response); + Some(response) + } + Err(e) => { + warn!( + bundle_hash = %bundle_hash, + error = %e, + "Metering failed for raw transaction" + ); + None + } + }; + + if let Some(meter_info) = meter_bundle_response.as_ref() { + self.metrics.successful_simulations.increment(1); + if self.send_to_builder { + _ = self.builder_tx.send(meter_info.clone()); + } + } else { + self.metrics.failed_simulations.increment(1); + } + + let accepted_bundle = + AcceptedBundle::new(parsed_bundle, meter_bundle_response.unwrap_or_default()); + + if send_to_kafka { + if let Err(e) = + self.bundle_queue_publisher.publish(&accepted_bundle, bundle_hash).await + { + warn!(message = "Failed to publish Queue::enqueue_bundle", bundle_hash = %bundle_hash, error = %e); + } + + self.metrics.sent_to_kafka.increment(1); + info!(message="queued singleton bundle", txn_hash=%transaction.tx_hash()); + } + + if send_to_mempool { + let response = + self.mempool_provider.send_raw_transaction(data.iter().as_slice()).await; + match response { + Ok(_) => { + self.metrics.sent_to_mempool.increment(1); + debug!(message = "sent transaction to the mempool", hash=%transaction.tx_hash()); + } + Err(e) => { + warn!(message = "Failed to send raw transaction to mempool", error = %e); + } + } + } + + info!( + message = "processed transaction", + bundle_hash = %bundle_hash, + transaction_hash = %transaction.tx_hash(), + ); + + self.send_audit_event(&accepted_bundle, accepted_bundle.bundle_hash()); + } + + self.metrics.send_raw_transaction_duration.record(start.elapsed().as_secs_f64()); + + Ok(transaction.tx_hash()) + } +} + +impl IngressService { + async fn get_tx(&self, data: &Bytes) -> RpcResult> { + if data.is_empty() { + return Err(EthApiError::EmptyRawTransactionData.into_rpc_err()); + } + + let envelope = OpTxEnvelope::decode_2718_exact(data.iter().as_slice()) + .map_err(|_| EthApiError::FailedToDecodeSignedTransaction.into_rpc_err())?; + + let transaction = envelope + .clone() + .try_into_recovered() + .map_err(|_| EthApiError::FailedToDecodeSignedTransaction.into_rpc_err())?; + Ok(transaction) + } + + async fn validate_bundle(&self, bundle: &Bundle) -> RpcResult<()> { + let start = Instant::now(); + if bundle.txs.is_empty() { + return Err(EthApiError::InvalidParams("Bundle cannot have empty transactions".into()) + .into_rpc_err()); + } + + let mut total_gas = 0u64; + let mut tx_hashes = Vec::new(); + for tx_data in &bundle.txs { + let transaction = self.get_tx(tx_data).await?; + total_gas = total_gas.saturating_add(transaction.gas_limit()); + tx_hashes.push(transaction.tx_hash()); + } + validate_bundle(bundle, total_gas, tx_hashes)?; + + self.metrics.validate_bundle_duration.record(start.elapsed().as_secs_f64()); + Ok(()) + } + + /// `meter_bundle` is used to determine how long a bundle will take to execute. A bundle that + /// is within `block_time_milliseconds` will return the `MeterBundleResponse` that can be passed along + /// to the builder. + async fn meter_bundle( + &self, + bundle: &Bundle, + bundle_hash: &B256, + ) -> RpcResult { + let start = Instant::now(); + let timeout_duration = Duration::from_millis(self.meter_bundle_timeout_ms); + + // The future we await has the nested type: + // Result< + // RpcResult, // 1. The inner operation's result + // tokio::time::error::Elapsed // 2. The outer timeout's result + // > + let res: MeterBundleResponse = timeout( + timeout_duration, + self.simulation_provider.client().request("base_meterBundle", (bundle,)), + ) + .await + .map_err(|_| { + warn!(message = "Timed out on requesting metering", bundle_hash = %bundle_hash); + EthApiError::InvalidParams("Timeout on requesting metering".into()).into_rpc_err() + })? + .map_err(|e| EthApiError::InvalidParams(e.to_string()).into_rpc_err())?; + + record_histogram(start.elapsed(), "base_meterBundle".to_string()); + + // we can save some builder payload building computation by not including bundles + // that we know will take longer than the block time to execute + let total_execution_time = (res.total_execution_time_us / 1_000) as u64; + if total_execution_time > self.block_time_milliseconds { + self.metrics.bundles_exceeded_metering_time.increment(1); + return Err( + EthApiError::InvalidParams("Bundle simulation took too long".into()).into_rpc_err() + ); + } + Ok(res) + } + + /// Helper method to validate, parse, and meter a bundle + async fn validate_parse_and_meter_bundle( + &self, + bundle: &Bundle, + to_meter: bool, + ) -> RpcResult<(AcceptedBundle, B256)> { + self.validate_bundle(bundle).await?; + let parsed_bundle: ParsedBundle = bundle + .clone() + .try_into() + .map_err(|e: String| EthApiError::InvalidParams(e).into_rpc_err())?; + let bundle_hash = parsed_bundle.bundle_hash(); + let meter_bundle_response = if to_meter { + self.meter_bundle(bundle, &bundle_hash).await? + } else { + MeterBundleResponse::default() + }; + let accepted_bundle = AcceptedBundle::new(parsed_bundle, meter_bundle_response.clone()); + Ok((accepted_bundle, bundle_hash)) + } + + /// Helper method to send audit event for a bundle + fn send_audit_event(&self, accepted_bundle: &AcceptedBundle, bundle_hash: B256) { + let audit_event = BundleEvent::Received { + bundle_id: *accepted_bundle.uuid(), + bundle: Box::new(accepted_bundle.clone()), + }; + if let Err(e) = self.audit_channel.send(audit_event) { + warn!( + message = "failed to send audit event", + bundle_hash = %bundle_hash, + error = %e + ); + } + } +} + +#[cfg(test)] +mod tests { + use std::{ + net::{IpAddr, SocketAddr}, + str::FromStr, + }; + + use alloy_provider::RootProvider; + use anyhow::Result; + use async_trait::async_trait; + use audit::test_utils::create_test_meter_bundle_response; + use jsonrpsee::{ + http_client::{HttpClient, HttpClientBuilder}, + server::{ServerBuilder, ServerHandle}, + }; + use mockall::mock; + use tokio::sync::{broadcast, mpsc}; + use url::Url; + use wiremock::{Mock, MockServer, ResponseTemplate, matchers::method}; + + use super::*; + use crate::{Config, TxSubmissionMethod, queue::MessageQueue}; + struct MockQueue; + + #[async_trait] + impl MessageQueue for MockQueue { + async fn publish(&self, _topic: &str, _key: &str, _payload: &[u8]) -> Result<()> { + Ok(()) + } + } + + fn create_test_config(mock_server: &MockServer) -> Config { + Config { + address: IpAddr::from([127, 0, 0, 1]), + port: 8080, + mempool_url: Url::parse("http://localhost:3000").unwrap(), + tx_submission_method: TxSubmissionMethod::Mempool, + ingress_kafka_properties: String::new(), + ingress_topic: String::new(), + audit_kafka_properties: String::new(), + audit_topic: String::new(), + log_level: String::from("info"), + log_format: utils::logger::LogFormat::Pretty, + send_transaction_default_lifetime_seconds: 300, + simulation_rpc: mock_server.uri().parse().unwrap(), + metrics_addr: SocketAddr::from(([127, 0, 0, 1], 9002)), + block_time_milliseconds: 1000, + meter_bundle_timeout_ms: 5000, + builder_rpcs: vec![], + max_buffered_meter_bundle_responses: 100, + max_buffered_backrun_bundles: 100, + health_check_addr: SocketAddr::from(([127, 0, 0, 1], 8081)), + backrun_enabled: false, + raw_tx_forward_rpc: None, + chain_id: 11, + max_backrun_txs: 5, + max_backrun_gas_limit: 5000000, + bundle_cache_ttl: 20, + send_to_builder: false, + } + } + + #[allow(dead_code)] + async fn setup_rpc_server(mock: MockIngressApi) -> (HttpClient, ServerHandle) { + let server = ServerBuilder::default().build("127.0.0.1:0").await.unwrap(); + + let addr = server.local_addr().unwrap(); + let handle = server.start(mock.into_rpc()); + + let client = HttpClientBuilder::default().build(format!("http://{}", addr)).unwrap(); + + (client, handle) + } + + #[tokio::test] + async fn test_timeout_logic() { + let timeout_duration = Duration::from_millis(100); + + // Test a future that takes longer than the timeout + let slow_future = async { + tokio::time::sleep(Duration::from_millis(200)).await; + Ok::(create_test_meter_bundle_response()) + }; + + let result = timeout(timeout_duration, slow_future) + .await + .map_err(|_| { + EthApiError::InvalidParams("Timeout on requesting metering".into()).into_rpc_err() + }) + .map_err(|e| e.to_string()); + + assert!(result.is_err()); + let error_string = format!("{:?}", result.unwrap_err()); + assert!(error_string.contains("Timeout on requesting metering")); + } + + #[tokio::test] + async fn test_timeout_logic_success() { + let timeout_duration = Duration::from_millis(200); + + // Test a future that completes within the timeout + let fast_future = async { + tokio::time::sleep(Duration::from_millis(50)).await; + Ok::(create_test_meter_bundle_response()) + }; + + let result = timeout(timeout_duration, fast_future) + .await + .map_err(|_| { + EthApiError::InvalidParams("Timeout on requesting metering".into()).into_rpc_err() + }) + .map_err(|e| e.to_string()); + + assert!(result.is_ok()); + // we're assumging that `base_meterBundle` will not error hence the second unwrap + let res = result.unwrap().unwrap(); + assert_eq!(res, create_test_meter_bundle_response()); + } + + // Replicate a failed `meter_bundle` request and instead of returning an error, we return a default `MeterBundleResponse` + #[tokio::test] + async fn test_meter_bundle_success() { + let mock_server = MockServer::start().await; + + // Mock error response from base_meterBundle + Mock::given(method("POST")) + .respond_with(ResponseTemplate::new(500).set_body_json(serde_json::json!({ + "jsonrpc": "2.0", + "id": 1, + "error": { + "code": -32000, + "message": "Simulation failed" + } + }))) + .mount(&mock_server) + .await; + + let config = create_test_config(&mock_server); + + let provider: RootProvider = + RootProvider::new_http(mock_server.uri().parse().unwrap()); + + let providers = Providers { + mempool: provider.clone(), + simulation: provider.clone(), + raw_tx_forward: None, + }; + + let (audit_tx, _audit_rx) = mpsc::unbounded_channel(); + let (builder_tx, _builder_rx) = broadcast::channel(1); + let (backrun_tx, _backrun_rx) = broadcast::channel(1); + + let service = + IngressService::new(providers, MockQueue, audit_tx, builder_tx, backrun_tx, config); + + let bundle = Bundle::default(); + let bundle_hash = B256::default(); + + let result = service.meter_bundle(&bundle, &bundle_hash).await; + + // Test that meter_bundle returns an error, but we handle it gracefully + assert!(result.is_err()); + let response = result.unwrap_or_else(|_| MeterBundleResponse::default()); + assert_eq!(response, MeterBundleResponse::default()); + } + + #[tokio::test] + async fn test_raw_tx_forward() { + let simulation_server = MockServer::start().await; + let forward_server = MockServer::start().await; + + // Mock error response from base_meterBundle + Mock::given(method("POST")) + .respond_with(ResponseTemplate::new(500).set_body_json(serde_json::json!({ + "jsonrpc": "2.0", + "id": 1, + "error": { + "code": -32000, + "message": "Simulation failed" + } + }))) + .mount(&simulation_server) + .await; + + // Mock forward endpoint - expect exactly 1 call + Mock::given(method("POST")) + .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({ + "jsonrpc": "2.0", + "id": 1, + "result": "0x0000000000000000000000000000000000000000000000000000000000000000" + }))) + .expect(1) + .mount(&forward_server) + .await; + + let mut config = create_test_config(&simulation_server); + config.tx_submission_method = TxSubmissionMethod::Kafka; // Skip mempool send + + let providers = Providers { + mempool: RootProvider::new_http(simulation_server.uri().parse().unwrap()), + simulation: RootProvider::new_http(simulation_server.uri().parse().unwrap()), + raw_tx_forward: Some(RootProvider::new_http(forward_server.uri().parse().unwrap())), + }; + + let (audit_tx, _audit_rx) = mpsc::unbounded_channel(); + let (builder_tx, _builder_rx) = broadcast::channel(1); + let (backrun_tx, _backrun_rx) = broadcast::channel(1); + + let service = + IngressService::new(providers, MockQueue, audit_tx, builder_tx, backrun_tx, config); + + // Valid signed transaction bytes + let tx_bytes = Bytes::from_str("0x02f86c0d010183072335825208940000000000000000000000000000000000000000872386f26fc1000080c001a0cdb9e4f2f1ba53f9429077e7055e078cf599786e29059cd80c5e0e923bb2c114a01c90e29201e031baf1da66296c3a5c15c200bcb5e6c34da2f05f7d1778f8be07").unwrap(); + + let result = service.send_raw_transaction(tx_bytes).await; + assert!(result.is_ok()); + + // Wait for spawned forward task to complete + tokio::time::sleep(Duration::from_millis(100)).await; + + // wiremock automatically verifies expect(1) when forward_server is dropped + } + mock! { + pub IngressApi {} + + #[async_trait] + impl IngressApiServer for IngressApi { + async fn send_bundle(&self, bundle: Bundle) -> RpcResult; + async fn send_backrun_bundle(&self, bundle: Bundle) -> RpcResult; + async fn cancel_bundle(&self, request: CancelBundle) -> RpcResult<()>; + async fn send_raw_transaction(&self, tx: Bytes) -> RpcResult; + } + } + + #[test] + fn test_validate_backrun_bundle_rejects_invalid() { + // Too few transactions (need at least 2: target + backrun) + let result = validate_backrun_bundle_limits(1, 21000, 5, 5000000); + assert!(result.is_err()); + assert!(result.unwrap_err().contains("at least 2 transactions")); + + // Exceeds max tx count + let result = validate_backrun_bundle_limits(6, 21000, 5, 5000000); + assert!(result.is_err()); + assert!(result.unwrap_err().contains("exceeds max transaction count")); + + // Exceeds max gas limit + let result = validate_backrun_bundle_limits(2, 6000000, 5, 5000000); + assert!(result.is_err()); + assert!(result.unwrap_err().contains("exceeds max gas limit")); + } +} diff --git a/crates/ingress-rpc/src/validation.rs b/crates/ingress-rpc/src/validation.rs new file mode 100644 index 0000000..df39af7 --- /dev/null +++ b/crates/ingress-rpc/src/validation.rs @@ -0,0 +1,359 @@ +use std::{ + collections::HashSet, + time::{Duration, SystemTime, UNIX_EPOCH}, +}; + +use alloy_consensus::private::alloy_eips::{BlockId, BlockNumberOrTag}; +use alloy_primitives::{Address, B256, U256}; +use alloy_provider::{Provider, RootProvider}; +use async_trait::async_trait; +use base_bundles::Bundle; +use base_reth_rpc_types::{EthApiError, SignError, extract_l1_info_from_tx}; +use jsonrpsee::core::RpcResult; +use op_alloy_network::Optimism; +use op_revm::l1block::L1BlockInfo; +use tokio::time::Instant; +use tracing::warn; + +use crate::metrics::record_histogram; + +const MAX_BUNDLE_GAS: u64 = 25_000_000; + +/// Account info for a given address +pub struct AccountInfo { + pub balance: U256, + pub nonce: u64, + pub code_hash: B256, +} + +/// Interface for fetching account info for a given address +#[async_trait] +pub trait AccountInfoLookup: Send + Sync { + async fn fetch_account_info(&self, address: Address) -> RpcResult; +} + +/// Implementation of the `AccountInfoLookup` trait for the `RootProvider` +#[async_trait] +impl AccountInfoLookup for RootProvider { + async fn fetch_account_info(&self, address: Address) -> RpcResult { + let start = Instant::now(); + let account = self + .get_account(address) + .await + .map_err(|_| EthApiError::Signing(SignError::NoAccount))?; + record_histogram(start.elapsed(), "eth_getAccount".to_string()); + + Ok(AccountInfo { + balance: account.balance, + nonce: account.nonce, + code_hash: account.code_hash, + }) + } +} + +/// Interface for fetching L1 block info for a given block number +#[async_trait] +pub trait L1BlockInfoLookup: Send + Sync { + async fn fetch_l1_block_info(&self) -> RpcResult; +} + +/// Implementation of the `L1BlockInfoLookup` trait for the `RootProvider` +#[async_trait] +impl L1BlockInfoLookup for RootProvider { + async fn fetch_l1_block_info(&self) -> RpcResult { + let start = Instant::now(); + let block = self + .get_block(BlockId::Number(BlockNumberOrTag::Latest)) + .full() + .await + .map_err(|e| { + warn!(message = "failed to fetch latest block", err = %e); + EthApiError::InternalEthError.into_rpc_err() + })? + .ok_or_else(|| { + warn!(message = "empty latest block returned"); + EthApiError::InternalEthError.into_rpc_err() + })?; + record_histogram(start.elapsed(), "eth_getBlockByNumber".to_string()); + + let txs = block.transactions.clone(); + let first_tx = txs.first_transaction().ok_or_else(|| { + warn!(message = "block contains no transactions"); + EthApiError::InternalEthError.into_rpc_err() + })?; + + Ok(extract_l1_info_from_tx(&first_tx.clone()).map_err(|e| { + warn!(message = "failed to extract l1_info from tx", err = %e); + EthApiError::InternalEthError.into_rpc_err() + })?) + } +} + +/// Helper function to validate propeties of a bundle. A bundle is valid if it satisfies the following criteria: +/// - The bundle's max_timestamp is not more than 1 hour in the future +/// - The bundle's gas limit is not greater than the maximum allowed gas limit +/// - The bundle can only contain 3 transactions at once +/// - Partial transaction dropping is not supported, `dropping_tx_hashes` must be empty +/// - revert protection is not supported, all transaction hashes must be in `reverting_tx_hashes` +pub fn validate_bundle(bundle: &Bundle, bundle_gas: u64, tx_hashes: Vec) -> RpcResult<()> { + // Don't allow bundles to be submitted over 1 hour into the future + // TODO: make the window configurable + let valid_timestamp_window = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs() + + Duration::from_secs(3600).as_secs(); + if let Some(max_timestamp) = bundle.max_timestamp + && max_timestamp > valid_timestamp_window + { + return Err(EthApiError::InvalidParams( + "Bundle cannot be more than 1 hour in the future".into(), + ) + .into_rpc_err()); + } + + // Check max gas limit for the entire bundle + if bundle_gas > MAX_BUNDLE_GAS { + return Err(EthApiError::InvalidParams("Bundle gas limit exceeds maximum allowed".into()) + .into_rpc_err()); + } + + // Can only provide 3 transactions at once + if bundle.txs.len() > 3 { + return Err(EthApiError::InvalidParams("Bundle can only contain 3 transactions".into()) + .into_rpc_err()); + } + + // Partial transaction dropping is not supported, `dropping_tx_hashes` must be empty + if !bundle.dropping_tx_hashes.is_empty() { + return Err(EthApiError::InvalidParams( + "Partial transaction dropping is not supported".into(), + ) + .into_rpc_err()); + } + + // revert protection: all transaction hashes must be in `reverting_tx_hashes` + let reverting_tx_hashes_set: HashSet<_> = bundle.reverting_tx_hashes.iter().collect(); + let tx_hashes_set: HashSet<_> = tx_hashes.iter().collect(); + if reverting_tx_hashes_set != tx_hashes_set { + return Err(EthApiError::InvalidParams( + "Revert protection is not supported. reverting_tx_hashes must include all hashes" + .into(), + ) + .into_rpc_err()); + } + + Ok(()) +} + +#[cfg(test)] +mod tests { + use std::time::{SystemTime, UNIX_EPOCH}; + + use alloy_consensus::{SignableTransaction, TxEip1559, transaction::SignerRecoverable}; + use alloy_primitives::{Bytes, bytes}; + use alloy_signer_local::PrivateKeySigner; + use op_alloy_consensus::OpTxEnvelope; + use op_alloy_network::{TxSignerSync, eip2718::Encodable2718}; + + use super::*; + + #[tokio::test] + async fn test_err_bundle_max_timestamp_too_far_in_the_future() { + let current_time = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs(); + let too_far_in_the_future = current_time + 3601; + let bundle = Bundle { + txs: vec![], + max_timestamp: Some(too_far_in_the_future), + ..Default::default() + }; + assert_eq!( + validate_bundle(&bundle, 0, vec![]), + Err(EthApiError::InvalidParams( + "Bundle cannot be more than 1 hour in the future".into() + ) + .into_rpc_err()) + ); + } + + #[tokio::test] + async fn test_err_bundle_max_gas_limit_too_high() { + let signer = PrivateKeySigner::random(); + let mut encoded_txs = vec![]; + let mut tx_hashes = vec![]; + + // Create transactions that collectively exceed MAX_BUNDLE_GAS (25M) + // Each transaction uses 4M gas, so 8 transactions = 32M gas > 25M limit + let gas = 4_000_000; + let mut total_gas = 0u64; + for _ in 0..8 { + let mut tx = TxEip1559 { + chain_id: 1, + nonce: 0, + gas_limit: gas, + max_fee_per_gas: 200000u128, + max_priority_fee_per_gas: 100000u128, + to: Address::random().into(), + value: U256::from(1000000u128), + access_list: Default::default(), + input: bytes!("").clone(), + }; + total_gas = total_gas.saturating_add(gas); + + let signature = signer.sign_transaction_sync(&mut tx).unwrap(); + let envelope = OpTxEnvelope::Eip1559(tx.into_signed(signature)); + let tx_hash = envelope.clone().try_into_recovered().unwrap().tx_hash(); + tx_hashes.push(tx_hash); + + // Encode the transaction + let mut encoded = vec![]; + envelope.encode_2718(&mut encoded); + encoded_txs.push(Bytes::from(encoded)); + } + + let bundle = Bundle { + txs: encoded_txs, + block_number: 0, + min_timestamp: None, + max_timestamp: None, + reverting_tx_hashes: vec![], + ..Default::default() + }; + + // Test should fail due to exceeding gas limit + let result = validate_bundle(&bundle, total_gas, tx_hashes); + assert!(result.is_err()); + if let Err(e) = result { + let error_message = format!("{e:?}"); + assert!(error_message.contains("Bundle gas limit exceeds maximum allowed")); + } + } + + #[tokio::test] + async fn test_err_bundle_too_many_transactions() { + let signer = PrivateKeySigner::random(); + let mut encoded_txs = vec![]; + let mut tx_hashes = vec![]; + + let gas = 4_000_000; + let mut total_gas = 0u64; + for _ in 0..4 { + let mut tx = TxEip1559 { + chain_id: 1, + nonce: 0, + gas_limit: gas, + max_fee_per_gas: 200000u128, + max_priority_fee_per_gas: 100000u128, + to: Address::random().into(), + value: U256::from(1000000u128), + access_list: Default::default(), + input: bytes!("").clone(), + }; + total_gas = total_gas.saturating_add(gas); + + let signature = signer.sign_transaction_sync(&mut tx).unwrap(); + let envelope = OpTxEnvelope::Eip1559(tx.into_signed(signature)); + let tx_hash = envelope.clone().try_into_recovered().unwrap().tx_hash(); + tx_hashes.push(tx_hash); + + // Encode the transaction + let mut encoded = vec![]; + envelope.encode_2718(&mut encoded); + encoded_txs.push(Bytes::from(encoded)); + } + + let bundle = Bundle { + txs: encoded_txs, + block_number: 0, + min_timestamp: None, + max_timestamp: None, + reverting_tx_hashes: vec![], + ..Default::default() + }; + + // Test should fail due to exceeding gas limit + let result = validate_bundle(&bundle, total_gas, tx_hashes); + assert!(result.is_err()); + if let Err(e) = result { + let error_message = format!("{e:?}"); + assert!(error_message.contains("Bundle can only contain 3 transactions")); + } + } + + #[tokio::test] + async fn test_err_bundle_partial_transaction_dropping_not_supported() { + let bundle = + Bundle { txs: vec![], dropping_tx_hashes: vec![B256::random()], ..Default::default() }; + assert_eq!( + validate_bundle(&bundle, 0, vec![]), + Err(EthApiError::InvalidParams("Partial transaction dropping is not supported".into()) + .into_rpc_err()) + ); + } + + #[tokio::test] + async fn test_err_bundle_not_all_tx_hashes_in_reverting_tx_hashes() { + let signer = PrivateKeySigner::random(); + let mut encoded_txs = vec![]; + let mut tx_hashes = vec![]; + + let gas = 4_000_000; + let mut total_gas = 0u64; + for _ in 0..4 { + let mut tx = TxEip1559 { + chain_id: 1, + nonce: 0, + gas_limit: gas, + max_fee_per_gas: 200000u128, + max_priority_fee_per_gas: 100000u128, + to: Address::random().into(), + value: U256::from(1000000u128), + access_list: Default::default(), + input: bytes!("").clone(), + }; + total_gas = total_gas.saturating_add(gas); + + let signature = signer.sign_transaction_sync(&mut tx).unwrap(); + let envelope = OpTxEnvelope::Eip1559(tx.into_signed(signature)); + let tx_hash = envelope.clone().try_into_recovered().unwrap().tx_hash(); + tx_hashes.push(tx_hash); + + // Encode the transaction + let mut encoded = vec![]; + envelope.encode_2718(&mut encoded); + encoded_txs.push(Bytes::from(encoded)); + } + + let bundle = Bundle { + txs: encoded_txs, + block_number: 0, + min_timestamp: None, + max_timestamp: None, + reverting_tx_hashes: tx_hashes[..2].to_vec(), + ..Default::default() + }; + + // Test should fail due to exceeding gas limit + let result = validate_bundle(&bundle, total_gas, tx_hashes); + assert!(result.is_err()); + if let Err(e) = result { + let error_message = format!("{e:?}"); + assert!(error_message.contains("Bundle can only contain 3 transactions")); + } + } + + #[tokio::test] + async fn test_decode_tx_rejects_empty_bytes() { + // Test that empty bytes fail to decode + use op_alloy_network::eip2718::Decodable2718; + let empty_bytes = Bytes::new(); + let result = OpTxEnvelope::decode_2718(&mut empty_bytes.as_ref()); + assert!(result.is_err(), "Empty bytes should fail decoding"); + } + + #[tokio::test] + async fn test_decode_tx_rejects_invalid_bytes() { + // Test that malformed bytes fail to decode + use op_alloy_network::eip2718::Decodable2718; + let invalid_bytes = Bytes::from(vec![0x01, 0x02, 0x03]); + let result = OpTxEnvelope::decode_2718(&mut invalid_bytes.as_ref()); + assert!(result.is_err(), "Invalid bytes should fail decoding"); + } +} diff --git a/crates/mempool-rebroadcaster/Cargo.toml b/crates/mempool-rebroadcaster/Cargo.toml index c562f63..e2d232a 100644 --- a/crates/mempool-rebroadcaster/Cargo.toml +++ b/crates/mempool-rebroadcaster/Cargo.toml @@ -14,7 +14,8 @@ path = "src/lib.rs" serde = { workspace = true } serde_json = { workspace = true } tracing = { workspace = true } -tokio = { workspace = true } +tracing-subscriber = { workspace = true, features = ["fmt", "std", "json", "env-filter"] } +tokio = { workspace = true, features = ["rt-multi-thread", "macros"] } # alloy alloy-primitives.workspace = true @@ -23,4 +24,5 @@ alloy-rpc-types = { workspace = true, features = ["txpool"] } alloy-rpc-types-eth.workspace = true alloy-consensus.workspace = true alloy-trie.workspace = true -alloy-provider = { workspace = true, features = ["txpool-api"] } +alloy-provider = { workspace = true, features = ["txpool-api", "reqwest"] } + diff --git a/crates/sidecrush/Cargo.toml b/crates/sidecrush/Cargo.toml index 10d8d15..89f6564 100644 --- a/crates/sidecrush/Cargo.toml +++ b/crates/sidecrush/Cargo.toml @@ -14,16 +14,14 @@ path = "src/lib.rs" anyhow = { workspace = true } async-trait = { workspace = true } cadence = { workspace = true } +tokio = { workspace = true, features = ["rt-multi-thread", "macros", "signal"] } tracing = { workspace = true } -tokio = { workspace = true } +tracing-subscriber = { workspace = true, features = ["fmt", "std", "json"] } # Ethereum client deps (will be used for header fetching) -alloy-provider = { workspace = true } -alloy-transport-http = { workspace = true } -alloy-rpc-types-eth = { workspace = true } alloy-consensus = { workspace = true } alloy-primitives = { workspace = true } +alloy-provider = { workspace = true, features = ["reqwest"] } +alloy-rpc-types-eth = { workspace = true } +alloy-transport-http = { workspace = true } -[dev-dependencies] -tokio = { workspace = true, features = ["rt-multi-thread", "macros"] } -tracing = { workspace = true } diff --git a/crates/utils/Cargo.toml b/crates/utils/Cargo.toml new file mode 100644 index 0000000..e875ce3 --- /dev/null +++ b/crates/utils/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "utils" +description = "Shared utility functions for logging, metrics, and config parsing" +version.workspace = true +edition.workspace = true +rust-version.workspace = true +license.workspace = true +homepage.workspace = true +repository.workspace = true + +[lints] +workspace = true + +[dependencies] +tracing = { workspace = true, features = ["std"] } +alloy-rpc-types = { workspace = true, features = ["eth"] } +metrics-exporter-prometheus = { workspace = true, features = ["http-listener"] } +tracing-subscriber = { workspace = true, features = ["std", "fmt", "ansi", "env-filter", "json"] } + +[dev-dependencies] +serde_json = { workspace = true, features = ["std"] } diff --git a/crates/utils/README.md b/crates/utils/README.md new file mode 100644 index 0000000..546ed46 --- /dev/null +++ b/crates/utils/README.md @@ -0,0 +1,3 @@ +# `utils` + +Shared utility functions for `base/infra` services — logging, metrics, and config parsing. diff --git a/crates/utils/src/kafka.rs b/crates/utils/src/kafka.rs new file mode 100644 index 0000000..ac07051 --- /dev/null +++ b/crates/utils/src/kafka.rs @@ -0,0 +1,21 @@ +use std::{collections::HashMap, fs}; + +pub fn load_kafka_config_from_file( + properties_file_path: &str, +) -> Result, std::io::Error> { + let kafka_properties = fs::read_to_string(properties_file_path)?; + + let mut config = HashMap::new(); + + for line in kafka_properties.lines() { + let line = line.trim(); + if line.is_empty() || line.starts_with('#') { + continue; + } + if let Some((key, value)) = line.split_once('=') { + config.insert(key.trim().to_string(), value.trim().to_string()); + } + } + + Ok(config) +} diff --git a/crates/utils/src/lib.rs b/crates/utils/src/lib.rs new file mode 100644 index 0000000..a6eacd8 --- /dev/null +++ b/crates/utils/src/lib.rs @@ -0,0 +1,11 @@ +#![doc = include_str!("../README.md")] +#![doc(issue_tracker_base_url = "https://github.com/base/infra/issues/")] +#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] +#![cfg_attr(not(test), warn(unused_crate_dependencies))] +#![allow(missing_docs)] + +use alloy_rpc_types as _; + +pub mod kafka; +pub mod logger; +pub mod metrics; diff --git a/crates/utils/src/logger.rs b/crates/utils/src/logger.rs new file mode 100644 index 0000000..ccdb8d2 --- /dev/null +++ b/crates/utils/src/logger.rs @@ -0,0 +1,63 @@ +use std::str::FromStr; + +use tracing::warn; +use tracing_subscriber::{fmt, layer::SubscriberExt, util::SubscriberInitExt}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum LogFormat { + Pretty, + Json, + Compact, +} + +impl FromStr for LogFormat { + type Err = String; + + fn from_str(s: &str) -> Result { + match s.to_lowercase().as_str() { + "json" => Ok(Self::Json), + "compact" => Ok(Self::Compact), + "pretty" => Ok(Self::Pretty), + _ => { + warn!("Invalid log format '{}', defaulting to 'pretty'", s); + Ok(Self::Pretty) + } + } + } +} + +pub fn init_logger(log_level: &str) { + init_logger_with_format(log_level, LogFormat::Pretty); +} + +pub fn init_logger_with_format(log_level: &str, format: LogFormat) { + let level = match log_level.to_lowercase().as_str() { + "trace" => tracing::Level::TRACE, + "debug" => tracing::Level::DEBUG, + "info" => tracing::Level::INFO, + "warn" => tracing::Level::WARN, + "error" => tracing::Level::ERROR, + _ => { + warn!("Invalid log level '{}', defaulting to 'info'", log_level); + tracing::Level::INFO + } + }; + + let env_filter = tracing_subscriber::EnvFilter::try_from_default_env() + .unwrap_or_else(|_| tracing_subscriber::EnvFilter::new(level.to_string())); + + match format { + LogFormat::Json => { + tracing_subscriber::registry() + .with(env_filter) + .with(fmt::layer().json().flatten_event(true).with_current_span(true)) + .init(); + } + LogFormat::Compact => { + tracing_subscriber::registry().with(env_filter).with(fmt::layer().compact()).init(); + } + LogFormat::Pretty => { + tracing_subscriber::registry().with(env_filter).with(fmt::layer().pretty()).init(); + } + } +} diff --git a/crates/utils/src/metrics.rs b/crates/utils/src/metrics.rs new file mode 100644 index 0000000..bb5f67f --- /dev/null +++ b/crates/utils/src/metrics.rs @@ -0,0 +1,10 @@ +use std::net::SocketAddr; + +use metrics_exporter_prometheus::PrometheusBuilder; + +pub fn init_prometheus_exporter(addr: SocketAddr) -> Result<(), Box> { + PrometheusBuilder::new() + .with_http_listener(addr) + .install() + .map_err(|e| Box::new(e) as Box) +} diff --git a/deny.toml b/deny.toml index 5c4adf5..3951543 100644 --- a/deny.toml +++ b/deny.toml @@ -48,11 +48,43 @@ skip = [ "foldhash", "lru", + # AWS SDK transitive dependencies + "aws-smithy-http", + "aws-smithy-json", + + # HTTP ecosystem (hyper 0.14 vs 1.x transition) + "h2", + "http", + "http-body", + "hyper", + "hyper-rustls", + + # TLS/crypto ecosystem + "rustls", + "rustls-webpki", + "tokio-rustls", + + # macOS security framework + "core-foundation", + "security-framework", + "openssl-probe", + # Random number generation "rand", "rand_chacha", "rand_core", + # Networking + "socket2", + + # OP Stack crates (reth uses older versions) + "op-alloy-consensus", + "op-alloy-rpc-types", + + # thiserror 1.x vs 2.x transition + "thiserror", + "thiserror-impl", + # Proc-macro / derive ecosystem (alloy-tx-macros vs ratatui/instability) "darling", "darling_core", diff --git a/justfile b/justfile index 43fcb90..0e2476a 100644 --- a/justfile +++ b/justfile @@ -105,3 +105,11 @@ run-mempool-rebroadcaster: # Run basectl with specified config (mainnet, sepolia, devnet, or path) basectl config="mainnet": cargo run -p basectl --release -- -c {{config}} + +# Run tips audit service +run-audit: + cargo run --bin audit + +# Run tips ingress RPC service +run-ingress-rpc: + cargo run --bin ingress-rpc diff --git a/ui/tips/.gitignore b/ui/tips/.gitignore new file mode 100644 index 0000000..5ef6a52 --- /dev/null +++ b/ui/tips/.gitignore @@ -0,0 +1,41 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/versions + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# env files (can opt-in for committing if needed) +.env* + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts diff --git a/ui/tips/Dockerfile b/ui/tips/Dockerfile new file mode 100644 index 0000000..b24abfd --- /dev/null +++ b/ui/tips/Dockerfile @@ -0,0 +1,40 @@ +FROM node:20-alpine AS deps +WORKDIR /app +COPY ui/tips/package.json ui/tips/yarn.lock ./ +RUN --mount=type=cache,target=/root/.yarn \ + yarn install --frozen-lockfile + +FROM node:20-alpine AS builder +WORKDIR /app +COPY --from=deps /app/node_modules ./node_modules +COPY ./ui/tips . + +ENV NEXT_TELEMETRY_DISABLED=1 + +RUN --mount=type=cache,target=/app/.next/cache \ + yarn build + +FROM node:20-alpine AS runner +WORKDIR /app + +ENV NODE_ENV=production +ENV NEXT_TELEMETRY_DISABLED=1 + +RUN addgroup --system --gid 1001 nodejs +RUN adduser --system --uid 1001 nextjs + +RUN mkdir .next +RUN chown nextjs:nodejs .next + +COPY --from=builder /app/public ./public +COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ +COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static + +USER nextjs + +EXPOSE 3000 + +ENV PORT=3000 +ENV HOSTNAME="0.0.0.0" + +CMD ["node", "server.js"] \ No newline at end of file diff --git a/ui/tips/biome.json b/ui/tips/biome.json new file mode 100644 index 0000000..31bf9c5 --- /dev/null +++ b/ui/tips/biome.json @@ -0,0 +1,43 @@ +{ + "$schema": "https://biomejs.dev/schemas/2.3.8/schema.json", + "vcs": { + "enabled": true, + "clientKind": "git", + "useIgnoreFile": true + }, + "files": { + "ignoreUnknown": true, + "includes": ["**", "!node_modules", "!.next", "!dist", "!build"] + }, + "css": { + "parser": { + "cssModules": true, + "tailwindDirectives": true + } + }, + "formatter": { + "enabled": true, + "indentStyle": "space", + "indentWidth": 2 + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true, + "suspicious": { + "noUnknownAtRules": "off" + } + }, + "domains": { + "next": "recommended", + "react": "recommended" + } + }, + "assist": { + "actions": { + "source": { + "organizeImports": "on" + } + } + } +} diff --git a/ui/tips/next.config.ts b/ui/tips/next.config.ts new file mode 100644 index 0000000..68a6c64 --- /dev/null +++ b/ui/tips/next.config.ts @@ -0,0 +1,7 @@ +import type { NextConfig } from "next"; + +const nextConfig: NextConfig = { + output: "standalone", +}; + +export default nextConfig; diff --git a/ui/tips/package.json b/ui/tips/package.json new file mode 100644 index 0000000..54d105c --- /dev/null +++ b/ui/tips/package.json @@ -0,0 +1,28 @@ +{ + "name": "ui", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev --turbopack", + "build": "next build --turbopack", + "start": "next start", + "lint": "biome check", + "format": "biome format --write" + }, + "dependencies": { + "@aws-sdk/client-s3": "3.940.0", + "next": "16.0.7", + "react": "19.2.1", + "react-dom": "19.2.1", + "viem": "2.40.3" + }, + "devDependencies": { + "@biomejs/biome": "2.3.8", + "@tailwindcss/postcss": "4.1.17", + "@types/node": "20.19.25", + "@types/react": "19.2.7", + "@types/react-dom": "19.2.3", + "tailwindcss": "4.1.17", + "typescript": "5.9.3" + } +} diff --git a/ui/tips/postcss.config.mjs b/ui/tips/postcss.config.mjs new file mode 100644 index 0000000..c7bcb4b --- /dev/null +++ b/ui/tips/postcss.config.mjs @@ -0,0 +1,5 @@ +const config = { + plugins: ["@tailwindcss/postcss"], +}; + +export default config; diff --git a/ui/tips/public/logo.svg b/ui/tips/public/logo.svg new file mode 100644 index 0000000..05f4921 --- /dev/null +++ b/ui/tips/public/logo.svg @@ -0,0 +1,12 @@ + + + + + + + + \ No newline at end of file diff --git a/ui/tips/src/app/api/block/[hash]/route.ts b/ui/tips/src/app/api/block/[hash]/route.ts new file mode 100644 index 0000000..aafe3c5 --- /dev/null +++ b/ui/tips/src/app/api/block/[hash]/route.ts @@ -0,0 +1,191 @@ +import { type NextRequest, NextResponse } from "next/server"; +import { type Block, createPublicClient, type Hash, http } from "viem"; +import { mainnet } from "viem/chains"; +import { + type BlockData, + type BlockTransaction, + cacheBlockData, + getBlockFromCache, + getBundleHistory, + getTransactionMetadataByHash, + type MeterBundleResult, +} from "@/lib/s3"; + +function serializeBlockData(block: BlockData) { + return { + ...block, + number: block.number.toString(), + timestamp: block.timestamp.toString(), + gasUsed: block.gasUsed.toString(), + gasLimit: block.gasLimit.toString(), + transactions: block.transactions.map((tx) => ({ + ...tx, + gasUsed: tx.gasUsed.toString(), + })), + }; +} + +const RPC_URL = process.env.TIPS_UI_RPC_URL || "http://localhost:8545"; + +const client = createPublicClient({ + chain: mainnet, + transport: http(RPC_URL), +}); + +async function fetchBlockFromRpc( + blockHash: string, +): Promise | null> { + try { + const block = await client.getBlock({ + blockHash: blockHash as Hash, + includeTransactions: true, + }); + return block; + } catch (error) { + console.error("Failed to fetch block from RPC:", error); + return null; + } +} + +// On OP Stack, the first transaction (index 0) is the L1 attributes deposit transaction. +// This is not a perfect check (ideally we'd check tx.type === 'deposit' or type 0x7e), +// but sufficient for filtering out system transactions that don't need simulation data. +function isSystemTransaction(tx: BlockTransaction): boolean { + return tx.index === 0; +} + +async function enrichTransactionWithBundleData( + txHash: string, +): Promise<{ bundleId: string | null; executionTimeUs: number | null }> { + const metadata = await getTransactionMetadataByHash(txHash); + if (!metadata || metadata.bundle_ids.length === 0) { + return { bundleId: null, executionTimeUs: null }; + } + + const bundleId = metadata.bundle_ids[0]; + const bundleHistory = await getBundleHistory(bundleId); + if (!bundleHistory) { + return { bundleId, executionTimeUs: null }; + } + + const receivedEvent = bundleHistory.history.find( + (e) => e.event === "Received", + ); + if (!receivedEvent?.data?.bundle?.meter_bundle_response?.results) { + return { bundleId, executionTimeUs: null }; + } + + const txResult = receivedEvent.data.bundle.meter_bundle_response.results.find( + (r: MeterBundleResult) => r.txHash.toLowerCase() === txHash.toLowerCase(), + ); + + return { + bundleId, + executionTimeUs: txResult?.executionTimeUs ?? null, + }; +} + +async function refetchMissingTransactionSimulations( + block: BlockData, +): Promise<{ updatedBlock: BlockData; hasUpdates: boolean }> { + const transactionsToRefetch = block.transactions.filter( + (tx) => tx.bundleId === null && !isSystemTransaction(tx), + ); + + if (transactionsToRefetch.length === 0) { + return { updatedBlock: block, hasUpdates: false }; + } + + const refetchResults = await Promise.all( + transactionsToRefetch.map(async (tx) => { + const { bundleId, executionTimeUs } = + await enrichTransactionWithBundleData(tx.hash); + return { hash: tx.hash, bundleId, executionTimeUs }; + }), + ); + + let hasUpdates = false; + const updatedTransactions = block.transactions.map((tx) => { + const refetchResult = refetchResults.find((r) => r.hash === tx.hash); + if (refetchResult && refetchResult.bundleId !== null) { + hasUpdates = true; + return { + ...tx, + bundleId: refetchResult.bundleId, + executionTimeUs: refetchResult.executionTimeUs, + }; + } + return tx; + }); + + return { + updatedBlock: { + ...block, + transactions: updatedTransactions, + cachedAt: hasUpdates ? Date.now() : block.cachedAt, + }, + hasUpdates, + }; +} + +export async function GET( + _request: NextRequest, + { params }: { params: Promise<{ hash: string }> }, +) { + try { + const { hash } = await params; + + const cachedBlock = await getBlockFromCache(hash); + if (cachedBlock) { + const { updatedBlock, hasUpdates } = + await refetchMissingTransactionSimulations(cachedBlock); + + if (hasUpdates) { + await cacheBlockData(updatedBlock); + } + + return NextResponse.json(serializeBlockData(updatedBlock)); + } + + const rpcBlock = await fetchBlockFromRpc(hash); + if (!rpcBlock || !rpcBlock.hash || !rpcBlock.number) { + return NextResponse.json({ error: "Block not found" }, { status: 404 }); + } + + const transactions: BlockTransaction[] = await Promise.all( + rpcBlock.transactions.map(async (tx, index) => { + const { bundleId, executionTimeUs } = + await enrichTransactionWithBundleData(tx.hash); + return { + hash: tx.hash, + from: tx.from, + to: tx.to, + gasUsed: tx.gas, + executionTimeUs, + bundleId, + index, + }; + }), + ); + + const blockData: BlockData = { + hash: rpcBlock.hash, + number: rpcBlock.number, + timestamp: rpcBlock.timestamp, + transactions, + gasUsed: rpcBlock.gasUsed, + gasLimit: rpcBlock.gasLimit, + cachedAt: Date.now(), + }; + + await cacheBlockData(blockData); + + return NextResponse.json(serializeBlockData(blockData)); + } catch (error) { + console.error("Error fetching block data:", error); + return NextResponse.json( + { error: "Internal server error" }, + { status: 500 }, + ); + } +} diff --git a/ui/tips/src/app/api/blocks/route.ts b/ui/tips/src/app/api/blocks/route.ts new file mode 100644 index 0000000..919256a --- /dev/null +++ b/ui/tips/src/app/api/blocks/route.ts @@ -0,0 +1,105 @@ +import { NextResponse } from "next/server"; + +const RPC_URL = process.env.TIPS_UI_RPC_URL || "http://localhost:8545"; + +export interface BlockSummary { + hash: string; + number: number; + timestamp: number; + transactionCount: number; +} + +export interface BlocksResponse { + blocks: BlockSummary[]; +} + +async function fetchLatestBlockNumber(): Promise { + try { + const response = await fetch(RPC_URL, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + jsonrpc: "2.0", + method: "eth_blockNumber", + params: [], + id: 1, + }), + }); + + const data = await response.json(); + if (data.error || !data.result) { + return null; + } + + return parseInt(data.result, 16); + } catch (error) { + console.error("Failed to fetch latest block number:", error); + return null; + } +} + +async function fetchBlockByNumber( + blockNumber: number, +): Promise { + try { + const response = await fetch(RPC_URL, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + jsonrpc: "2.0", + method: "eth_getBlockByNumber", + params: [`0x${blockNumber.toString(16)}`, false], + id: 1, + }), + }); + + const data = await response.json(); + if (data.error || !data.result) { + return null; + } + + const block = data.result; + return { + hash: block.hash, + number: parseInt(block.number, 16), + timestamp: parseInt(block.timestamp, 16), + transactionCount: block.transactions?.length ?? 0, + }; + } catch (error) { + console.error(`Failed to fetch block ${blockNumber}:`, error); + return null; + } +} + +export async function GET() { + try { + const latestBlockNumber = await fetchLatestBlockNumber(); + if (latestBlockNumber === null) { + return NextResponse.json( + { error: "Failed to fetch latest block" }, + { status: 500 }, + ); + } + + const blockNumbers = Array.from( + { length: 10 }, + (_, i) => latestBlockNumber - i, + ).filter((n) => n >= 0); + + const blocks = await Promise.all(blockNumbers.map(fetchBlockByNumber)); + + const validBlocks = blocks.filter( + (block): block is BlockSummary => block !== null, + ); + + const response: BlocksResponse = { blocks: validBlocks }; + + return NextResponse.json(response); + } catch (error) { + console.error("Error fetching blocks:", error); + return NextResponse.json( + { error: "Internal server error" }, + { status: 500 }, + ); + } +} diff --git a/ui/tips/src/app/api/bundle/[uuid]/route.ts b/ui/tips/src/app/api/bundle/[uuid]/route.ts new file mode 100644 index 0000000..6be37d6 --- /dev/null +++ b/ui/tips/src/app/api/bundle/[uuid]/route.ts @@ -0,0 +1,39 @@ +import { type NextRequest, NextResponse } from "next/server"; +import { type BundleEvent, getBundleHistory } from "@/lib/s3"; + +export interface BundleHistoryResponse { + uuid: string; + history: BundleEvent[]; +} + +export async function GET( + _request: NextRequest, + { params }: { params: Promise<{ uuid: string }> }, +) { + try { + const { uuid } = await params; + + const bundle = await getBundleHistory(uuid); + if (!bundle) { + return NextResponse.json({ error: "Bundle not found" }, { status: 404 }); + } + + const history = bundle.history; + history.sort((lhs, rhs) => + lhs.data.timestamp < rhs.data.timestamp ? -1 : 1, + ); + + const response: BundleHistoryResponse = { + uuid, + history: bundle.history, + }; + + return NextResponse.json(response); + } catch (error) { + console.error("Error fetching bundle data:", error); + return NextResponse.json( + { error: "Internal server error" }, + { status: 500 }, + ); + } +} diff --git a/ui/tips/src/app/api/health/route.ts b/ui/tips/src/app/api/health/route.ts new file mode 100644 index 0000000..35adb41 --- /dev/null +++ b/ui/tips/src/app/api/health/route.ts @@ -0,0 +1,5 @@ +import { NextResponse } from "next/server"; + +export async function GET() { + return NextResponse.json({ status: "ok" }, { status: 200 }); +} diff --git a/ui/tips/src/app/api/txn/[hash]/route.ts b/ui/tips/src/app/api/txn/[hash]/route.ts new file mode 100644 index 0000000..44f6824 --- /dev/null +++ b/ui/tips/src/app/api/txn/[hash]/route.ts @@ -0,0 +1,73 @@ +import { type NextRequest, NextResponse } from "next/server"; +import { + type BundleEvent, + getBundleHistory, + getTransactionMetadataByHash, +} from "@/lib/s3"; + +export interface TransactionEvent { + type: string; + data: { + bundle_id?: string; + transactions?: Array<{ + id: { + sender: string; + nonce: string; + hash: string; + }; + data: string; + }>; + transaction_ids?: Array<{ + sender: string; + nonce: string; + hash: string; + }>; + block_number?: number; + flashblock_index?: number; + block_hash?: string; + }; +} + +export interface TransactionHistoryResponse { + hash: string; + bundle_ids: string[]; + history: BundleEvent[]; +} + +export async function GET( + _request: NextRequest, + { params }: { params: Promise<{ hash: string }> }, +) { + try { + const { hash } = await params; + + const metadata = await getTransactionMetadataByHash(hash); + + if (!metadata) { + return NextResponse.json( + { error: "Transaction not found" }, + { status: 404 }, + ); + } + + // TODO: Can be in multiple bundles + const bundle = await getBundleHistory(metadata.bundle_ids[0]); + if (!bundle) { + return NextResponse.json({ error: "Bundle not found" }, { status: 404 }); + } + + const response: TransactionHistoryResponse = { + hash, + bundle_ids: metadata.bundle_ids, + history: bundle.history, + }; + + return NextResponse.json(response); + } catch (error) { + console.error("Error fetching transaction data:", error); + return NextResponse.json( + { error: "Internal server error" }, + { status: 500 }, + ); + } +} diff --git a/ui/tips/src/app/block/[hash]/page.tsx b/ui/tips/src/app/block/[hash]/page.tsx new file mode 100644 index 0000000..71133e0 --- /dev/null +++ b/ui/tips/src/app/block/[hash]/page.tsx @@ -0,0 +1,426 @@ +"use client"; + +import Link from "next/link"; +import { useEffect, useState } from "react"; +import type { BlockData, BlockTransaction } from "@/lib/s3"; + +const BLOCK_EXPLORER_URL = process.env.NEXT_PUBLIC_BLOCK_EXPLORER_URL; + +interface PageProps { + params: Promise<{ hash: string }>; +} + +function CopyButton({ text }: { text: string }) { + const [copied, setCopied] = useState(false); + + const handleCopy = async () => { + await navigator.clipboard.writeText(text); + setCopied(true); + setTimeout(() => setCopied(false), 2000); + }; + + return ( + + ); +} + +function Card({ + children, + className = "", +}: { + children: React.ReactNode; + className?: string; +}) { + return ( +

+ {children} +
+ ); +} + +function getHeatmapStyle( + executionTimeUs: number, + maxTime: number, +): { bg: string; text: string } { + if (maxTime === 0) return { bg: "bg-amber-50", text: "text-amber-700" }; + const ratio = Math.min(executionTimeUs / maxTime, 1); + if (ratio < 0.2) return { bg: "bg-amber-100", text: "text-amber-800" }; + if (ratio < 0.4) return { bg: "bg-amber-200", text: "text-amber-900" }; + if (ratio < 0.6) return { bg: "bg-orange-200", text: "text-orange-900" }; + if (ratio < 0.8) return { bg: "bg-orange-300", text: "text-orange-950" }; + return { bg: "bg-red-300", text: "text-red-950" }; +} + +function TransactionRow({ + tx, + maxExecutionTime, +}: { + tx: BlockTransaction; + maxExecutionTime: number; +}) { + const hasBundle = tx.bundleId !== null; + const hasExecutionTime = tx.executionTimeUs !== null; + const executionTime = tx.executionTimeUs ?? 0; + const heatmapStyle = hasExecutionTime + ? getHeatmapStyle(executionTime, maxExecutionTime) + : null; + + const content = ( +
+
+ {tx.index} +
+
+
+ {BLOCK_EXPLORER_URL ? ( + e.stopPropagation()} + > + {tx.hash} + + ) : ( + + {tx.hash} + + )} +
+
+ {tx.from.slice(0, 6)}...{tx.from.slice(-4)} + {tx.to && ( + <> + {" → "} + {tx.to.slice(0, 6)}...{tx.to.slice(-4)} + + )} +
+
+
+ {hasExecutionTime && heatmapStyle ? ( + + {executionTime.toLocaleString()}μs + + ) : ( +
—
+ )} +
+ {tx.gasUsed.toLocaleString()} gas +
+
+
+ ); + + if (hasBundle) { + return {content}; + } + + return content; +} + +function BlockStats({ block }: { block: BlockData }) { + const txsWithTime = block.transactions.filter( + (tx) => tx.executionTimeUs !== null, + ); + const totalExecutionTime = txsWithTime.reduce( + (sum, tx) => sum + (tx.executionTimeUs ?? 0), + 0, + ); + const bundleCount = block.transactions.filter( + (tx) => tx.bundleId !== null, + ).length; + + return ( + +
+
+
+
Block Number
+
+ #{block.number.toLocaleString()} +
+
+
+
Transactions
+
+ {block.transactions.length} +
+
+
+
Bundles
+
+ {bundleCount} +
+
+
+
Total Exec Time
+
+ {totalExecutionTime > 0 + ? `${totalExecutionTime.toLocaleString()}μs` + : "—"} +
+
+
+
+
+
+ Gas Used + + {block.gasUsed.toLocaleString()} + +
+
+ Gas Limit + + {block.gasLimit.toLocaleString()} + +
+
+ Timestamp + + {new Date(Number(block.timestamp) * 1000).toLocaleString()} + +
+
+
+ ); +} + +export default function BlockPage({ params }: PageProps) { + const [hash, setHash] = useState(""); + const [data, setData] = useState(null); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); + + useEffect(() => { + params.then((p) => setHash(p.hash)); + }, [params]); + + useEffect(() => { + if (!hash) return; + + const fetchData = async () => { + try { + const response = await fetch(`/api/block/${hash}`); + if (!response.ok) { + setError( + response.status === 404 + ? "Block not found" + : "Failed to fetch block data", + ); + setData(null); + return; + } + setData(await response.json()); + setError(null); + } catch { + setError("Failed to fetch block data"); + setData(null); + } finally { + setLoading(false); + } + }; + + fetchData(); + }, [hash]); + + if (!hash || loading) { + return ( +
+
+
+ Loading block... +
+
+ ); + } + + const maxExecutionTime = data + ? Math.max( + ...data.transactions + .filter((tx) => tx.executionTimeUs !== null) + .map((tx) => tx.executionTimeUs ?? 0), + 0, + ) + : 0; + + return ( +
+
+
+
+ + + Back + + + +
+ + TIPS + +
+
+ + {hash.slice(0, 10)}...{hash.slice(-8)} + + + {BLOCK_EXPLORER_URL && ( + + + External link + + + + )} +
+
+
+ +
+ {error && ( + +
+
+ + Error + + +
+
+

Error

+

{error}

+
+
+
+ )} + + {data && ( +
+
+

+ Block Overview +

+ +
+ +
+

+ Transactions +

+ +
+
#
+
Transaction
+
Execution
+
+
+ {data.transactions.map((tx) => ( + + ))} +
+ {data.transactions.length === 0 && ( +
+ No transactions in this block +
+ )} +
+
+
+ )} +
+
+ ); +} diff --git a/ui/tips/src/app/bundles/[uuid]/page.tsx b/ui/tips/src/app/bundles/[uuid]/page.tsx new file mode 100644 index 0000000..0212106 --- /dev/null +++ b/ui/tips/src/app/bundles/[uuid]/page.tsx @@ -0,0 +1,592 @@ +"use client"; + +import Link from "next/link"; +import { useEffect, useState } from "react"; +import type { BundleHistoryResponse } from "@/app/api/bundle/[uuid]/route"; +import type { BundleTransaction, MeterBundleResponse } from "@/lib/s3"; + +const WEI_PER_GWEI = 10n ** 9n; +const WEI_PER_ETH = 10n ** 18n; +const BLOCK_EXPLORER_URL = process.env.NEXT_PUBLIC_BLOCK_EXPLORER_URL; + +interface PageProps { + params: Promise<{ uuid: string }>; +} + +function formatBigInt(value: bigint, decimals: number, scale: bigint): string { + const whole = value / scale; + const frac = ((value % scale) * 10n ** BigInt(decimals)) / scale; + return `${whole}.${frac.toString().padStart(decimals, "0")}`; +} + +function formatHexValue(hex: string | undefined): string { + if (!hex) return "—"; + const value = BigInt(hex); + if (value >= WEI_PER_ETH / 10000n) { + return `${formatBigInt(value, 6, WEI_PER_ETH)} ETH`; + } + if (value >= WEI_PER_GWEI / 100n) { + return `${formatBigInt(value, 4, WEI_PER_GWEI)} Gwei`; + } + return `${value.toString()} Wei`; +} + +function formatGasPrice(hex: string | undefined): string { + if (!hex) return "—"; + const value = BigInt(hex); + return `${formatBigInt(value, 2, WEI_PER_GWEI)} Gwei`; +} + +function ExplorerLink({ + type, + value, + children, + className = "", +}: { + type: "tx" | "address"; + value: string; + children: React.ReactNode; + className?: string; +}) { + if (!BLOCK_EXPLORER_URL) { + return {children}; + } + + const path = type === "tx" ? `/tx/${value}` : `/address/${value}`; + return ( + + {children} + + ); +} + +function CopyButton({ text }: { text: string }) { + const [copied, setCopied] = useState(false); + + const handleCopy = async () => { + await navigator.clipboard.writeText(text); + setCopied(true); + setTimeout(() => setCopied(false), 2000); + }; + + return ( + + ); +} + +function Badge({ + children, + variant = "default", +}: { + children: React.ReactNode; + variant?: "default" | "success" | "warning" | "error"; +}) { + const variants = { + default: "bg-blue-50 text-blue-700 ring-blue-600/20", + success: "bg-emerald-50 text-emerald-700 ring-emerald-600/20", + warning: "bg-amber-50 text-amber-700 ring-amber-600/20", + error: "bg-red-50 text-red-700 ring-red-600/20", + }; + + return ( + + {children} + + ); +} + +function Card({ + children, + className = "", +}: { + children: React.ReactNode; + className?: string; +}) { + return ( +
+ {children} +
+ ); +} + +function TransactionDetails({ + tx, + index, +}: { + tx: BundleTransaction; + index: number; +}) { + const [expanded, setExpanded] = useState(index === 0); + + return ( +
+ + + {expanded && ( + <> +
+ + + + + + + + + + + + + + + +
Hash + + + {tx.hash} + + + +
From + + + {tx.signer} + + + +
To + + + {tx.to} + + + +
+
+
+
+ Nonce + + {parseInt(tx.nonce, 16)} + +
+
+ Max Fee + + {formatGasPrice(tx.maxFeePerGas)} + +
+
+ Priority Fee + + {formatGasPrice(tx.maxPriorityFeePerGas)} + +
+
+ Type + + {tx.type === "0x2" ? "EIP-1559" : tx.type} + +
+
+ + )} +
+ ); +} + +function SimulationCard({ meter }: { meter: MeterBundleResponse }) { + return ( + +
+
+
+
Total Gas
+
+ {meter.totalGasUsed.toLocaleString()} +
+
+
+
Execution Time
+
+ {meter.results.reduce((sum, r) => sum + r.executionTimeUs, 0)}μs +
+
+
+
Gas Price
+
+ {formatGasPrice(meter.bundleGasPrice)} +
+
+
+
Coinbase Diff
+
+ {formatHexValue(meter.coinbaseDiff)} +
+
+
+
+
+
+ State Block + + #{meter.stateBlockNumber} + +
+
+ Gas Fees + + {formatHexValue(meter.gasFees)} + +
+
+ ETH to Coinbase + + {formatHexValue(meter.ethSentToCoinbase)} + +
+
+
+ ); +} + +function TimelineEventDetails({ + event, +}: { + event: BundleHistoryResponse["history"][0]; +}) { + if (event.event === "BlockIncluded" && event.data?.block_hash) { + return ( +
+ {event.event} + + Block #{event.data.block_number} + +
+ ); + } + + if (event.event === "BuilderIncluded" && event.data?.builder) { + return ( +
+ {event.event} + + {event.data.builder} (flashblock #{event.data.flashblock_index}) + +
+ ); + } + + if (event.event === "Dropped" && event.data?.reason) { + return ( +
+ {event.event} + {event.data.reason} +
+ ); + } + + return {event.event}; +} + +function Timeline({ events }: { events: BundleHistoryResponse["history"] }) { + if (events.length === 0) return null; + + return ( +
+ {events.map((event, index) => ( +
+
+
+
+
+ + +
+
+ ))} +
+ ); +} + +function SectionTitle({ children }: { children: React.ReactNode }) { + return ( +

{children}

+ ); +} + +export default function BundlePage({ params }: PageProps) { + const [uuid, setUuid] = useState(""); + const [data, setData] = useState(null); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); + + useEffect(() => { + params.then((p) => setUuid(p.uuid)); + }, [params]); + + useEffect(() => { + if (!uuid) return; + + const fetchData = async () => { + try { + const response = await fetch(`/api/bundle/${uuid}`); + if (!response.ok) { + setError( + response.status === 404 + ? "Bundle not found" + : "Failed to fetch bundle data", + ); + setData(null); + return; + } + setData(await response.json()); + setError(null); + } catch { + setError("Failed to fetch bundle data"); + setData(null); + } finally { + setLoading(false); + } + }; + + fetchData(); + const interval = setInterval(fetchData, 5000); + return () => clearInterval(interval); + }, [uuid]); + + if (!uuid || (loading && !data)) { + return ( +
+
+
+ Loading bundle... +
+
+ ); + } + + const latestBundle = data?.history + .filter((e) => e.data?.bundle) + .map((e) => e.data.bundle) + .pop(); + + return ( +
+
+
+
+ + + Back + + + +
+ + TIPS + +
+
+ + {uuid} + + +
+
+
+ +
+ {error && ( + +
+
+ + Error + + +
+
+

Error

+

{error}

+
+
+
+ )} + + {data && latestBundle && ( +
+
+ Transactions +
+ {latestBundle.txs.map((tx, index) => ( + + ))} +
+
+ + {latestBundle.meter_bundle_response && ( +
+ Simulation Results + +
+ )} + +
+ Event History + + {data.history.length > 0 ? ( + + ) : ( +
+ No events recorded yet. +
+ )} +
+
+
+ )} +
+
+ ); +} diff --git a/ui/tips/src/app/globals.css b/ui/tips/src/app/globals.css new file mode 100644 index 0000000..a2dc41e --- /dev/null +++ b/ui/tips/src/app/globals.css @@ -0,0 +1,26 @@ +@import "tailwindcss"; + +:root { + --background: #ffffff; + --foreground: #171717; +} + +@theme inline { + --color-background: var(--background); + --color-foreground: var(--foreground); + --font-sans: var(--font-geist-sans); + --font-mono: var(--font-geist-mono); +} + +@media (prefers-color-scheme: dark) { + :root { + --background: #0a0a0a; + --foreground: #ededed; + } +} + +body { + background: var(--background); + color: var(--foreground); + font-family: Arial, Helvetica, sans-serif; +} diff --git a/ui/tips/src/app/layout.tsx b/ui/tips/src/app/layout.tsx new file mode 100644 index 0000000..bc9a9f2 --- /dev/null +++ b/ui/tips/src/app/layout.tsx @@ -0,0 +1,34 @@ +import type { Metadata } from "next"; +import { Geist, Geist_Mono } from "next/font/google"; +import "./globals.css"; + +const geistSans = Geist({ + variable: "--font-geist-sans", + subsets: ["latin"], +}); + +const geistMono = Geist_Mono({ + variable: "--font-geist-mono", + subsets: ["latin"], +}); + +export const metadata: Metadata = { + title: "TIPS", + description: "A beautiful UI for interacting with TIPS", +}; + +export default function RootLayout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { + return ( + + + {children} + + + ); +} diff --git a/ui/tips/src/app/page.tsx b/ui/tips/src/app/page.tsx new file mode 100644 index 0000000..21e257f --- /dev/null +++ b/ui/tips/src/app/page.tsx @@ -0,0 +1,257 @@ +"use client"; + +import Link from "next/link"; +import { useRouter } from "next/navigation"; +import { useEffect, useState } from "react"; +import type { BlockSummary, BlocksResponse } from "./api/blocks/route"; + +function SearchBar({ onError }: { onError: (error: string | null) => void }) { + const router = useRouter(); + const [searchHash, setSearchHash] = useState(""); + const [loading, setLoading] = useState(false); + + const handleSearch = async (e: React.FormEvent) => { + e.preventDefault(); + const hash = searchHash.trim(); + if (!hash) return; + + setLoading(true); + onError(null); + + try { + const response = await fetch(`/api/txn/${hash}`); + if (!response.ok) { + if (response.status === 404) { + onError("Transaction not found"); + } else { + onError("Failed to fetch transaction data"); + } + return; + } + const result = await response.json(); + + if (result.bundle_ids && result.bundle_ids.length > 0) { + router.push(`/bundles/${result.bundle_ids[0]}`); + } else { + onError("No bundle found for this transaction"); + } + } catch { + onError("Failed to fetch transaction data"); + } finally { + setLoading(false); + } + }; + + return ( +
+ setSearchHash(e.target.value)} + className="w-64 lg:w-80 px-3 py-1.5 text-sm border rounded-lg bg-white border-gray-300 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent placeholder-gray-400" + disabled={loading} + /> + +
+ ); +} + +function BlockRow({ block, index }: { block: BlockSummary; index: number }) { + const opacity = Math.max(0.3, 1 - index * 0.08); + const timeSince = Math.floor(Date.now() / 1000 - block.timestamp); + const timeAgo = + timeSince <= 0 + ? "now" + : timeSince < 60 + ? `${timeSince}s ago` + : timeSince < 3600 + ? `${Math.floor(timeSince / 60)}m ago` + : `${Math.floor(timeSince / 3600)}h ago`; + + return ( + +
+ + Block + + +
+
+
+ + #{block.number.toLocaleString()} + + {timeAgo} +
+
+ {block.hash} +
+
+
+
+ {block.transactionCount} +
+
txns
+
+ + View + + + + ); +} + +function Card({ + children, + className = "", +}: { + children: React.ReactNode; + className?: string; +}) { + return ( +
+ {children} +
+ ); +} + +export default function Home() { + const [error, setError] = useState(null); + const [blocks, setBlocks] = useState([]); + const [loading, setLoading] = useState(true); + + useEffect(() => { + const fetchBlocks = async () => { + try { + const response = await fetch("/api/blocks"); + if (response.ok) { + const data: BlocksResponse = await response.json(); + setBlocks(data.blocks); + } + } catch { + console.error("Failed to fetch blocks"); + } finally { + setLoading(false); + } + }; + + fetchBlocks(); + const interval = setInterval(fetchBlocks, 2000); + return () => clearInterval(interval); + }, []); + + return ( +
+
+
+ TIPS + +
+
+ +
+ {error && ( + +
+ + Error + + + {error} + +
+
+ )} + +
+

+ Latest Blocks +

+ + + {loading ? ( +
+
+
+ Loading blocks... +
+
+ ) : blocks.length > 0 ? ( +
+ {blocks.map((block, index) => ( + + ))} +
+ ) : ( +
+ No blocks available +
+ )} + +
+
+
+ ); +} diff --git a/ui/tips/src/app/txn/[hash]/page.tsx b/ui/tips/src/app/txn/[hash]/page.tsx new file mode 100644 index 0000000..76f1dda --- /dev/null +++ b/ui/tips/src/app/txn/[hash]/page.tsx @@ -0,0 +1,79 @@ +"use client"; + +import { useRouter } from "next/navigation"; +import { useEffect, useState } from "react"; +import type { TransactionHistoryResponse } from "@/app/api/txn/[hash]/route"; + +interface PageProps { + params: Promise<{ hash: string }>; +} + +export default function TransactionRedirectPage({ params }: PageProps) { + const router = useRouter(); + const [hash, setHash] = useState(""); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); + + useEffect(() => { + const initializeParams = async () => { + const resolvedParams = await params; + setHash(resolvedParams.hash); + }; + initializeParams(); + }, [params]); + + useEffect(() => { + if (!hash) return; + + const fetchAndRedirect = async () => { + try { + const response = await fetch(`/api/txn/${hash}`); + if (!response.ok) { + if (response.status === 404) { + setError("Transaction not found"); + } else { + setError("Failed to fetch transaction data"); + } + return; + } + const result: TransactionHistoryResponse = await response.json(); + + if (result.bundle_ids && result.bundle_ids.length > 0) { + router.push(`/bundles/${result.bundle_ids[0]}`); + } else { + setError("No bundle found for this transaction"); + } + } catch (_err) { + setError("Failed to fetch transaction data"); + } finally { + setLoading(false); + } + }; + + fetchAndRedirect(); + }, [hash, router]); + + if (!hash) { + return ( +
+
Loading...
+
+ ); + } + + return ( +
+
+

Transaction {hash}

+ {loading && ( +
+ Redirecting to bundle page... +
+ )} + {error && ( +
{error}
+ )} +
+
+ ); +} diff --git a/ui/tips/src/lib/s3.ts b/ui/tips/src/lib/s3.ts new file mode 100644 index 0000000..0d0cde7 --- /dev/null +++ b/ui/tips/src/lib/s3.ts @@ -0,0 +1,250 @@ +import { + GetObjectCommand, + PutObjectCommand, + S3Client, + type S3ClientConfig, +} from "@aws-sdk/client-s3"; + +function createS3Client(): S3Client { + const configType = process.env.TIPS_UI_S3_CONFIG_TYPE || "aws"; + const region = process.env.TIPS_UI_AWS_REGION || "us-east-1"; + + if (configType === "manual") { + console.log("Using Manual S3 configuration"); + const config: S3ClientConfig = { + region, + forcePathStyle: true, + }; + + if (process.env.TIPS_UI_S3_ENDPOINT) { + config.endpoint = process.env.TIPS_UI_S3_ENDPOINT; + } + + if ( + process.env.TIPS_UI_S3_ACCESS_KEY_ID && + process.env.TIPS_UI_S3_SECRET_ACCESS_KEY + ) { + config.credentials = { + accessKeyId: process.env.TIPS_UI_S3_ACCESS_KEY_ID, + secretAccessKey: process.env.TIPS_UI_S3_SECRET_ACCESS_KEY, + }; + } + + return new S3Client(config); + } + + console.log("Using AWS S3 configuration"); + return new S3Client({ + region, + }); +} + +const s3Client = createS3Client(); + +const BUCKET_NAME = process.env.TIPS_UI_S3_BUCKET_NAME || "tips"; + +export interface TransactionMetadata { + bundle_ids: string[]; + sender: string; + nonce: string; +} + +async function getObjectContent(key: string): Promise { + try { + const command = new GetObjectCommand({ + Bucket: BUCKET_NAME, + Key: key, + }); + + const response = await s3Client.send(command); + const body = await response.Body?.transformToString(); + return body || null; + } catch (_error) { + return null; + } +} + +export async function getTransactionMetadataByHash( + hash: string, +): Promise { + const key = `transactions/by_hash/${hash}`; + const content = await getObjectContent(key); + + if (!content) { + return null; + } + + try { + return JSON.parse(content) as TransactionMetadata; + } catch (error) { + console.error( + `Failed to parse transaction metadata for hash ${hash}:`, + error, + ); + return null; + } +} + +export interface BundleTransaction { + signer: string; + type: string; + chainId: string; + nonce: string; + gas: string; + maxFeePerGas: string; + maxPriorityFeePerGas: string; + to: string; + value: string; + accessList: unknown[]; + input: string; + r: string; + s: string; + yParity: string; + v: string; + hash: string; +} + +export interface MeterBundleResult { + coinbaseDiff: string; + ethSentToCoinbase: string; + fromAddress: string; + gasFees: string; + gasPrice: string; + gasUsed: number; + toAddress: string; + txHash: string; + value: string; + executionTimeUs: number; +} + +export interface MeterBundleResponse { + bundleGasPrice: string; + bundleHash: string; + coinbaseDiff: string; + ethSentToCoinbase: string; + gasFees: string; + results: MeterBundleResult[]; + stateBlockNumber: number; + totalGasUsed: number; + totalExecutionTimeUs: number; +} + +export interface BundleData { + uuid: string; + txs: BundleTransaction[]; + block_number: string; + max_timestamp: number; + reverting_tx_hashes: string[]; + meter_bundle_response: MeterBundleResponse; +} + +export interface BundleEventData { + key: string; + timestamp: number; + bundle?: BundleData; + block_number?: number; + block_hash?: string; + builder?: string; + flashblock_index?: number; + reason?: string; +} + +export interface BundleEvent { + event: string; + data: BundleEventData; +} + +export interface BundleHistory { + history: BundleEvent[]; +} + +export async function getBundleHistory( + bundleId: string, +): Promise { + const key = `bundles/${bundleId}`; + const content = await getObjectContent(key); + + if (!content) { + return null; + } + + try { + return JSON.parse(content) as BundleHistory; + } catch (error) { + console.error( + `Failed to parse bundle history for bundle ${bundleId}:`, + error, + ); + return null; + } +} + +export interface BlockTransaction { + hash: string; + from: string; + to: string | null; + gasUsed: bigint; + executionTimeUs: number | null; + bundleId: string | null; + index: number; +} + +export interface BlockData { + hash: string; + number: bigint; + timestamp: bigint; + transactions: BlockTransaction[]; + gasUsed: bigint; + gasLimit: bigint; + cachedAt: number; +} + +export async function getBlockFromCache( + blockHash: string, +): Promise { + const key = `blocks/${blockHash}`; + const content = await getObjectContent(key); + + if (!content) { + return null; + } + + try { + const parsed = JSON.parse(content); + return { + ...parsed, + number: BigInt(parsed.number), + timestamp: BigInt(parsed.timestamp), + gasUsed: BigInt(parsed.gasUsed), + gasLimit: BigInt(parsed.gasLimit), + transactions: parsed.transactions.map( + (tx: BlockTransaction & { gasUsed: string }) => ({ + ...tx, + gasUsed: BigInt(tx.gasUsed), + }), + ), + } as BlockData; + } catch (error) { + console.error(`Failed to parse block data for hash ${blockHash}:`, error); + return null; + } +} + +export async function cacheBlockData(blockData: BlockData): Promise { + const key = `blocks/${blockData.hash}`; + + try { + const command = new PutObjectCommand({ + Bucket: BUCKET_NAME, + Key: key, + Body: JSON.stringify(blockData, (_, value) => + typeof value === "bigint" ? value.toString() : value, + ), + ContentType: "application/json", + }); + + await s3Client.send(command); + } catch (error) { + console.error(`Failed to cache block data for ${blockData.hash}:`, error); + } +} diff --git a/ui/tips/tsconfig.json b/ui/tips/tsconfig.json new file mode 100644 index 0000000..0f96f2a --- /dev/null +++ b/ui/tips/tsconfig.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "target": "ES2020", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "react-jsx", + "incremental": true, + "plugins": [ + { + "name": "next" + } + ], + "paths": { + "@/*": ["./src/*"] + } + }, + "include": [ + "next-env.d.ts", + "**/*.ts", + "**/*.tsx", + ".next/types/**/*.ts", + ".next/dev/types/**/*.ts" + ], + "exclude": ["node_modules"] +} diff --git a/ui/tips/yarn.lock b/ui/tips/yarn.lock new file mode 100644 index 0000000..f687ad4 --- /dev/null +++ b/ui/tips/yarn.lock @@ -0,0 +1,1912 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@adraffy/ens-normalize@^1.11.0": + version "1.11.1" + resolved "https://registry.npmjs.org/@adraffy/ens-normalize/-/ens-normalize-1.11.1.tgz" + integrity sha512-nhCBV3quEgesuf7c7KYfperqSS14T8bYuvJ8PcLJp6znkZpFc0AuW4qBtr8eKVyPPe/8RSr7sglCWPU5eaxwKQ== + +"@alloc/quick-lru@^5.2.0": + version "5.2.0" + resolved "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz" + integrity sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw== + +"@aws-crypto/crc32@5.2.0": + version "5.2.0" + resolved "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-5.2.0.tgz" + integrity sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg== + dependencies: + "@aws-crypto/util" "^5.2.0" + "@aws-sdk/types" "^3.222.0" + tslib "^2.6.2" + +"@aws-crypto/crc32c@5.2.0": + version "5.2.0" + resolved "https://registry.npmjs.org/@aws-crypto/crc32c/-/crc32c-5.2.0.tgz" + integrity sha512-+iWb8qaHLYKrNvGRbiYRHSdKRWhto5XlZUEBwDjYNf+ly5SVYG6zEoYIdxvf5R3zyeP16w4PLBn3rH1xc74Rag== + dependencies: + "@aws-crypto/util" "^5.2.0" + "@aws-sdk/types" "^3.222.0" + tslib "^2.6.2" + +"@aws-crypto/sha1-browser@5.2.0": + version "5.2.0" + resolved "https://registry.npmjs.org/@aws-crypto/sha1-browser/-/sha1-browser-5.2.0.tgz" + integrity sha512-OH6lveCFfcDjX4dbAvCFSYUjJZjDr/3XJ3xHtjn3Oj5b9RjojQo8npoLeA/bNwkOkrSQ0wgrHzXk4tDRxGKJeg== + dependencies: + "@aws-crypto/supports-web-crypto" "^5.2.0" + "@aws-crypto/util" "^5.2.0" + "@aws-sdk/types" "^3.222.0" + "@aws-sdk/util-locate-window" "^3.0.0" + "@smithy/util-utf8" "^2.0.0" + tslib "^2.6.2" + +"@aws-crypto/sha256-browser@5.2.0": + version "5.2.0" + resolved "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz" + integrity sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw== + dependencies: + "@aws-crypto/sha256-js" "^5.2.0" + "@aws-crypto/supports-web-crypto" "^5.2.0" + "@aws-crypto/util" "^5.2.0" + "@aws-sdk/types" "^3.222.0" + "@aws-sdk/util-locate-window" "^3.0.0" + "@smithy/util-utf8" "^2.0.0" + tslib "^2.6.2" + +"@aws-crypto/sha256-js@5.2.0", "@aws-crypto/sha256-js@^5.2.0": + version "5.2.0" + resolved "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz" + integrity sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA== + dependencies: + "@aws-crypto/util" "^5.2.0" + "@aws-sdk/types" "^3.222.0" + tslib "^2.6.2" + +"@aws-crypto/supports-web-crypto@^5.2.0": + version "5.2.0" + resolved "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-5.2.0.tgz" + integrity sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg== + dependencies: + tslib "^2.6.2" + +"@aws-crypto/util@5.2.0", "@aws-crypto/util@^5.2.0": + version "5.2.0" + resolved "https://registry.npmjs.org/@aws-crypto/util/-/util-5.2.0.tgz" + integrity sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ== + dependencies: + "@aws-sdk/types" "^3.222.0" + "@smithy/util-utf8" "^2.0.0" + tslib "^2.6.2" + +"@aws-sdk/client-s3@3.940.0": + version "3.940.0" + resolved "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.940.0.tgz" + integrity sha512-Wi4qnBT6shRRMXuuTgjMFTU5mu2KFWisgcigEMPptjPGUtJvBVi4PTGgS64qsLoUk/obqDAyOBOfEtRZ2ddC2w== + dependencies: + "@aws-crypto/sha1-browser" "5.2.0" + "@aws-crypto/sha256-browser" "5.2.0" + "@aws-crypto/sha256-js" "5.2.0" + "@aws-sdk/core" "3.940.0" + "@aws-sdk/credential-provider-node" "3.940.0" + "@aws-sdk/middleware-bucket-endpoint" "3.936.0" + "@aws-sdk/middleware-expect-continue" "3.936.0" + "@aws-sdk/middleware-flexible-checksums" "3.940.0" + "@aws-sdk/middleware-host-header" "3.936.0" + "@aws-sdk/middleware-location-constraint" "3.936.0" + "@aws-sdk/middleware-logger" "3.936.0" + "@aws-sdk/middleware-recursion-detection" "3.936.0" + "@aws-sdk/middleware-sdk-s3" "3.940.0" + "@aws-sdk/middleware-ssec" "3.936.0" + "@aws-sdk/middleware-user-agent" "3.940.0" + "@aws-sdk/region-config-resolver" "3.936.0" + "@aws-sdk/signature-v4-multi-region" "3.940.0" + "@aws-sdk/types" "3.936.0" + "@aws-sdk/util-endpoints" "3.936.0" + "@aws-sdk/util-user-agent-browser" "3.936.0" + "@aws-sdk/util-user-agent-node" "3.940.0" + "@smithy/config-resolver" "^4.4.3" + "@smithy/core" "^3.18.5" + "@smithy/eventstream-serde-browser" "^4.2.5" + "@smithy/eventstream-serde-config-resolver" "^4.3.5" + "@smithy/eventstream-serde-node" "^4.2.5" + "@smithy/fetch-http-handler" "^5.3.6" + "@smithy/hash-blob-browser" "^4.2.6" + "@smithy/hash-node" "^4.2.5" + "@smithy/hash-stream-node" "^4.2.5" + "@smithy/invalid-dependency" "^4.2.5" + "@smithy/md5-js" "^4.2.5" + "@smithy/middleware-content-length" "^4.2.5" + "@smithy/middleware-endpoint" "^4.3.12" + "@smithy/middleware-retry" "^4.4.12" + "@smithy/middleware-serde" "^4.2.6" + "@smithy/middleware-stack" "^4.2.5" + "@smithy/node-config-provider" "^4.3.5" + "@smithy/node-http-handler" "^4.4.5" + "@smithy/protocol-http" "^5.3.5" + "@smithy/smithy-client" "^4.9.8" + "@smithy/types" "^4.9.0" + "@smithy/url-parser" "^4.2.5" + "@smithy/util-base64" "^4.3.0" + "@smithy/util-body-length-browser" "^4.2.0" + "@smithy/util-body-length-node" "^4.2.1" + "@smithy/util-defaults-mode-browser" "^4.3.11" + "@smithy/util-defaults-mode-node" "^4.2.14" + "@smithy/util-endpoints" "^3.2.5" + "@smithy/util-middleware" "^4.2.5" + "@smithy/util-retry" "^4.2.5" + "@smithy/util-stream" "^4.5.6" + "@smithy/util-utf8" "^4.2.0" + "@smithy/util-waiter" "^4.2.5" + tslib "^2.6.2" + +"@aws-sdk/client-sso@3.940.0": + version "3.940.0" + resolved "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.940.0.tgz" + integrity sha512-SdqJGWVhmIURvCSgkDditHRO+ozubwZk9aCX9MK8qxyOndhobCndW1ozl3hX9psvMAo9Q4bppjuqy/GHWpjB+A== + dependencies: + "@aws-crypto/sha256-browser" "5.2.0" + "@aws-crypto/sha256-js" "5.2.0" + "@aws-sdk/core" "3.940.0" + "@aws-sdk/middleware-host-header" "3.936.0" + "@aws-sdk/middleware-logger" "3.936.0" + "@aws-sdk/middleware-recursion-detection" "3.936.0" + "@aws-sdk/middleware-user-agent" "3.940.0" + "@aws-sdk/region-config-resolver" "3.936.0" + "@aws-sdk/types" "3.936.0" + "@aws-sdk/util-endpoints" "3.936.0" + "@aws-sdk/util-user-agent-browser" "3.936.0" + "@aws-sdk/util-user-agent-node" "3.940.0" + "@smithy/config-resolver" "^4.4.3" + "@smithy/core" "^3.18.5" + "@smithy/fetch-http-handler" "^5.3.6" + "@smithy/hash-node" "^4.2.5" + "@smithy/invalid-dependency" "^4.2.5" + "@smithy/middleware-content-length" "^4.2.5" + "@smithy/middleware-endpoint" "^4.3.12" + "@smithy/middleware-retry" "^4.4.12" + "@smithy/middleware-serde" "^4.2.6" + "@smithy/middleware-stack" "^4.2.5" + "@smithy/node-config-provider" "^4.3.5" + "@smithy/node-http-handler" "^4.4.5" + "@smithy/protocol-http" "^5.3.5" + "@smithy/smithy-client" "^4.9.8" + "@smithy/types" "^4.9.0" + "@smithy/url-parser" "^4.2.5" + "@smithy/util-base64" "^4.3.0" + "@smithy/util-body-length-browser" "^4.2.0" + "@smithy/util-body-length-node" "^4.2.1" + "@smithy/util-defaults-mode-browser" "^4.3.11" + "@smithy/util-defaults-mode-node" "^4.2.14" + "@smithy/util-endpoints" "^3.2.5" + "@smithy/util-middleware" "^4.2.5" + "@smithy/util-retry" "^4.2.5" + "@smithy/util-utf8" "^4.2.0" + tslib "^2.6.2" + +"@aws-sdk/core@3.940.0": + version "3.940.0" + resolved "https://registry.npmjs.org/@aws-sdk/core/-/core-3.940.0.tgz" + integrity sha512-KsGD2FLaX5ngJao1mHxodIVU9VYd1E8810fcYiGwO1PFHDzf5BEkp6D9IdMeQwT8Q6JLYtiiT1Y/o3UCScnGoA== + dependencies: + "@aws-sdk/types" "3.936.0" + "@aws-sdk/xml-builder" "3.930.0" + "@smithy/core" "^3.18.5" + "@smithy/node-config-provider" "^4.3.5" + "@smithy/property-provider" "^4.2.5" + "@smithy/protocol-http" "^5.3.5" + "@smithy/signature-v4" "^5.3.5" + "@smithy/smithy-client" "^4.9.8" + "@smithy/types" "^4.9.0" + "@smithy/util-base64" "^4.3.0" + "@smithy/util-middleware" "^4.2.5" + "@smithy/util-utf8" "^4.2.0" + tslib "^2.6.2" + +"@aws-sdk/credential-provider-env@3.940.0": + version "3.940.0" + resolved "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.940.0.tgz" + integrity sha512-/G3l5/wbZYP2XEQiOoIkRJmlv15f1P3MSd1a0gz27lHEMrOJOGq66rF1Ca4OJLzapWt3Fy9BPrZAepoAX11kMw== + dependencies: + "@aws-sdk/core" "3.940.0" + "@aws-sdk/types" "3.936.0" + "@smithy/property-provider" "^4.2.5" + "@smithy/types" "^4.9.0" + tslib "^2.6.2" + +"@aws-sdk/credential-provider-http@3.940.0": + version "3.940.0" + resolved "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.940.0.tgz" + integrity sha512-dOrc03DHElNBD6N9Okt4U0zhrG4Wix5QUBSZPr5VN8SvmjD9dkrrxOkkJaMCl/bzrW7kbQEp7LuBdbxArMmOZQ== + dependencies: + "@aws-sdk/core" "3.940.0" + "@aws-sdk/types" "3.936.0" + "@smithy/fetch-http-handler" "^5.3.6" + "@smithy/node-http-handler" "^4.4.5" + "@smithy/property-provider" "^4.2.5" + "@smithy/protocol-http" "^5.3.5" + "@smithy/smithy-client" "^4.9.8" + "@smithy/types" "^4.9.0" + "@smithy/util-stream" "^4.5.6" + tslib "^2.6.2" + +"@aws-sdk/credential-provider-ini@3.940.0": + version "3.940.0" + resolved "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.940.0.tgz" + integrity sha512-gn7PJQEzb/cnInNFTOaDoCN/hOKqMejNmLof1W5VW95Qk0TPO52lH8R4RmJPnRrwFMswOWswTOpR1roKNLIrcw== + dependencies: + "@aws-sdk/core" "3.940.0" + "@aws-sdk/credential-provider-env" "3.940.0" + "@aws-sdk/credential-provider-http" "3.940.0" + "@aws-sdk/credential-provider-login" "3.940.0" + "@aws-sdk/credential-provider-process" "3.940.0" + "@aws-sdk/credential-provider-sso" "3.940.0" + "@aws-sdk/credential-provider-web-identity" "3.940.0" + "@aws-sdk/nested-clients" "3.940.0" + "@aws-sdk/types" "3.936.0" + "@smithy/credential-provider-imds" "^4.2.5" + "@smithy/property-provider" "^4.2.5" + "@smithy/shared-ini-file-loader" "^4.4.0" + "@smithy/types" "^4.9.0" + tslib "^2.6.2" + +"@aws-sdk/credential-provider-login@3.940.0": + version "3.940.0" + resolved "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.940.0.tgz" + integrity sha512-fOKC3VZkwa9T2l2VFKWRtfHQPQuISqqNl35ZhcXjWKVwRwl/o7THPMkqI4XwgT2noGa7LLYVbWMwnsgSsBqglg== + dependencies: + "@aws-sdk/core" "3.940.0" + "@aws-sdk/nested-clients" "3.940.0" + "@aws-sdk/types" "3.936.0" + "@smithy/property-provider" "^4.2.5" + "@smithy/protocol-http" "^5.3.5" + "@smithy/shared-ini-file-loader" "^4.4.0" + "@smithy/types" "^4.9.0" + tslib "^2.6.2" + +"@aws-sdk/credential-provider-node@3.940.0": + version "3.940.0" + resolved "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.940.0.tgz" + integrity sha512-M8NFAvgvO6xZjiti5kztFiAYmSmSlG3eUfr4ZHSfXYZUA/KUdZU/D6xJyaLnU8cYRWBludb6K9XPKKVwKfqm4g== + dependencies: + "@aws-sdk/credential-provider-env" "3.940.0" + "@aws-sdk/credential-provider-http" "3.940.0" + "@aws-sdk/credential-provider-ini" "3.940.0" + "@aws-sdk/credential-provider-process" "3.940.0" + "@aws-sdk/credential-provider-sso" "3.940.0" + "@aws-sdk/credential-provider-web-identity" "3.940.0" + "@aws-sdk/types" "3.936.0" + "@smithy/credential-provider-imds" "^4.2.5" + "@smithy/property-provider" "^4.2.5" + "@smithy/shared-ini-file-loader" "^4.4.0" + "@smithy/types" "^4.9.0" + tslib "^2.6.2" + +"@aws-sdk/credential-provider-process@3.940.0": + version "3.940.0" + resolved "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.940.0.tgz" + integrity sha512-pILBzt5/TYCqRsJb7vZlxmRIe0/T+FZPeml417EK75060ajDGnVJjHcuVdLVIeKoTKm9gmJc9l45gon6PbHyUQ== + dependencies: + "@aws-sdk/core" "3.940.0" + "@aws-sdk/types" "3.936.0" + "@smithy/property-provider" "^4.2.5" + "@smithy/shared-ini-file-loader" "^4.4.0" + "@smithy/types" "^4.9.0" + tslib "^2.6.2" + +"@aws-sdk/credential-provider-sso@3.940.0": + version "3.940.0" + resolved "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.940.0.tgz" + integrity sha512-q6JMHIkBlDCOMnA3RAzf8cGfup+8ukhhb50fNpghMs1SNBGhanmaMbZSgLigBRsPQW7fOk2l8jnzdVLS+BB9Uw== + dependencies: + "@aws-sdk/client-sso" "3.940.0" + "@aws-sdk/core" "3.940.0" + "@aws-sdk/token-providers" "3.940.0" + "@aws-sdk/types" "3.936.0" + "@smithy/property-provider" "^4.2.5" + "@smithy/shared-ini-file-loader" "^4.4.0" + "@smithy/types" "^4.9.0" + tslib "^2.6.2" + +"@aws-sdk/credential-provider-web-identity@3.940.0": + version "3.940.0" + resolved "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.940.0.tgz" + integrity sha512-9QLTIkDJHHaYL0nyymO41H8g3ui1yz6Y3GmAN1gYQa6plXisuFBnGAbmKVj7zNvjWaOKdF0dV3dd3AFKEDoJ/w== + dependencies: + "@aws-sdk/core" "3.940.0" + "@aws-sdk/nested-clients" "3.940.0" + "@aws-sdk/types" "3.936.0" + "@smithy/property-provider" "^4.2.5" + "@smithy/shared-ini-file-loader" "^4.4.0" + "@smithy/types" "^4.9.0" + tslib "^2.6.2" + +"@aws-sdk/middleware-bucket-endpoint@3.936.0": + version "3.936.0" + resolved "https://registry.npmjs.org/@aws-sdk/middleware-bucket-endpoint/-/middleware-bucket-endpoint-3.936.0.tgz" + integrity sha512-XLSVVfAorUxZh6dzF+HTOp4R1B5EQcdpGcPliWr0KUj2jukgjZEcqbBmjyMF/p9bmyQsONX80iURF1HLAlW0qg== + dependencies: + "@aws-sdk/types" "3.936.0" + "@aws-sdk/util-arn-parser" "3.893.0" + "@smithy/node-config-provider" "^4.3.5" + "@smithy/protocol-http" "^5.3.5" + "@smithy/types" "^4.9.0" + "@smithy/util-config-provider" "^4.2.0" + tslib "^2.6.2" + +"@aws-sdk/middleware-expect-continue@3.936.0": + version "3.936.0" + resolved "https://registry.npmjs.org/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.936.0.tgz" + integrity sha512-Eb4ELAC23bEQLJmUMYnPWcjD3FZIsmz2svDiXEcxRkQU9r7NRID7pM7C5NPH94wOfiCk0b2Y8rVyFXW0lGQwbA== + dependencies: + "@aws-sdk/types" "3.936.0" + "@smithy/protocol-http" "^5.3.5" + "@smithy/types" "^4.9.0" + tslib "^2.6.2" + +"@aws-sdk/middleware-flexible-checksums@3.940.0": + version "3.940.0" + resolved "https://registry.npmjs.org/@aws-sdk/middleware-flexible-checksums/-/middleware-flexible-checksums-3.940.0.tgz" + integrity sha512-WdsxDAVj5qaa5ApAP+JbpCOMHFGSmzjs2Y2OBSbWPeR9Ew7t/Okj+kUub94QJPsgzhvU1/cqNejhsw5VxeFKSQ== + dependencies: + "@aws-crypto/crc32" "5.2.0" + "@aws-crypto/crc32c" "5.2.0" + "@aws-crypto/util" "5.2.0" + "@aws-sdk/core" "3.940.0" + "@aws-sdk/types" "3.936.0" + "@smithy/is-array-buffer" "^4.2.0" + "@smithy/node-config-provider" "^4.3.5" + "@smithy/protocol-http" "^5.3.5" + "@smithy/types" "^4.9.0" + "@smithy/util-middleware" "^4.2.5" + "@smithy/util-stream" "^4.5.6" + "@smithy/util-utf8" "^4.2.0" + tslib "^2.6.2" + +"@aws-sdk/middleware-host-header@3.936.0": + version "3.936.0" + resolved "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.936.0.tgz" + integrity sha512-tAaObaAnsP1XnLGndfkGWFuzrJYuk9W0b/nLvol66t8FZExIAf/WdkT2NNAWOYxljVs++oHnyHBCxIlaHrzSiw== + dependencies: + "@aws-sdk/types" "3.936.0" + "@smithy/protocol-http" "^5.3.5" + "@smithy/types" "^4.9.0" + tslib "^2.6.2" + +"@aws-sdk/middleware-location-constraint@3.936.0": + version "3.936.0" + resolved "https://registry.npmjs.org/@aws-sdk/middleware-location-constraint/-/middleware-location-constraint-3.936.0.tgz" + integrity sha512-SCMPenDtQMd9o5da9JzkHz838w3327iqXk3cbNnXWqnNRx6unyW8FL0DZ84gIY12kAyVHz5WEqlWuekc15ehfw== + dependencies: + "@aws-sdk/types" "3.936.0" + "@smithy/types" "^4.9.0" + tslib "^2.6.2" + +"@aws-sdk/middleware-logger@3.936.0": + version "3.936.0" + resolved "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.936.0.tgz" + integrity sha512-aPSJ12d3a3Ea5nyEnLbijCaaYJT2QjQ9iW+zGh5QcZYXmOGWbKVyPSxmVOboZQG+c1M8t6d2O7tqrwzIq8L8qw== + dependencies: + "@aws-sdk/types" "3.936.0" + "@smithy/types" "^4.9.0" + tslib "^2.6.2" + +"@aws-sdk/middleware-recursion-detection@3.936.0": + version "3.936.0" + resolved "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.936.0.tgz" + integrity sha512-l4aGbHpXM45YNgXggIux1HgsCVAvvBoqHPkqLnqMl9QVapfuSTjJHfDYDsx1Xxct6/m7qSMUzanBALhiaGO2fA== + dependencies: + "@aws-sdk/types" "3.936.0" + "@aws/lambda-invoke-store" "^0.2.0" + "@smithy/protocol-http" "^5.3.5" + "@smithy/types" "^4.9.0" + tslib "^2.6.2" + +"@aws-sdk/middleware-sdk-s3@3.940.0": + version "3.940.0" + resolved "https://registry.npmjs.org/@aws-sdk/middleware-sdk-s3/-/middleware-sdk-s3-3.940.0.tgz" + integrity sha512-JYkLjgS1wLoKHJ40G63+afM1ehmsPsjcmrHirKh8+kSCx4ip7+nL1e/twV4Zicxr8RJi9Y0Ahq5mDvneilDDKQ== + dependencies: + "@aws-sdk/core" "3.940.0" + "@aws-sdk/types" "3.936.0" + "@aws-sdk/util-arn-parser" "3.893.0" + "@smithy/core" "^3.18.5" + "@smithy/node-config-provider" "^4.3.5" + "@smithy/protocol-http" "^5.3.5" + "@smithy/signature-v4" "^5.3.5" + "@smithy/smithy-client" "^4.9.8" + "@smithy/types" "^4.9.0" + "@smithy/util-config-provider" "^4.2.0" + "@smithy/util-middleware" "^4.2.5" + "@smithy/util-stream" "^4.5.6" + "@smithy/util-utf8" "^4.2.0" + tslib "^2.6.2" + +"@aws-sdk/middleware-ssec@3.936.0": + version "3.936.0" + resolved "https://registry.npmjs.org/@aws-sdk/middleware-ssec/-/middleware-ssec-3.936.0.tgz" + integrity sha512-/GLC9lZdVp05ozRik5KsuODR/N7j+W+2TbfdFL3iS+7un+gnP6hC8RDOZd6WhpZp7drXQ9guKiTAxkZQwzS8DA== + dependencies: + "@aws-sdk/types" "3.936.0" + "@smithy/types" "^4.9.0" + tslib "^2.6.2" + +"@aws-sdk/middleware-user-agent@3.940.0": + version "3.940.0" + resolved "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.940.0.tgz" + integrity sha512-nJbLrUj6fY+l2W2rIB9P4Qvpiy0tnTdg/dmixRxrU1z3e8wBdspJlyE+AZN4fuVbeL6rrRrO/zxQC1bB3cw5IA== + dependencies: + "@aws-sdk/core" "3.940.0" + "@aws-sdk/types" "3.936.0" + "@aws-sdk/util-endpoints" "3.936.0" + "@smithy/core" "^3.18.5" + "@smithy/protocol-http" "^5.3.5" + "@smithy/types" "^4.9.0" + tslib "^2.6.2" + +"@aws-sdk/nested-clients@3.940.0": + version "3.940.0" + resolved "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.940.0.tgz" + integrity sha512-x0mdv6DkjXqXEcQj3URbCltEzW6hoy/1uIL+i8gExP6YKrnhiZ7SzuB4gPls2UOpK5UqLiqXjhRLfBb1C9i4Dw== + dependencies: + "@aws-crypto/sha256-browser" "5.2.0" + "@aws-crypto/sha256-js" "5.2.0" + "@aws-sdk/core" "3.940.0" + "@aws-sdk/middleware-host-header" "3.936.0" + "@aws-sdk/middleware-logger" "3.936.0" + "@aws-sdk/middleware-recursion-detection" "3.936.0" + "@aws-sdk/middleware-user-agent" "3.940.0" + "@aws-sdk/region-config-resolver" "3.936.0" + "@aws-sdk/types" "3.936.0" + "@aws-sdk/util-endpoints" "3.936.0" + "@aws-sdk/util-user-agent-browser" "3.936.0" + "@aws-sdk/util-user-agent-node" "3.940.0" + "@smithy/config-resolver" "^4.4.3" + "@smithy/core" "^3.18.5" + "@smithy/fetch-http-handler" "^5.3.6" + "@smithy/hash-node" "^4.2.5" + "@smithy/invalid-dependency" "^4.2.5" + "@smithy/middleware-content-length" "^4.2.5" + "@smithy/middleware-endpoint" "^4.3.12" + "@smithy/middleware-retry" "^4.4.12" + "@smithy/middleware-serde" "^4.2.6" + "@smithy/middleware-stack" "^4.2.5" + "@smithy/node-config-provider" "^4.3.5" + "@smithy/node-http-handler" "^4.4.5" + "@smithy/protocol-http" "^5.3.5" + "@smithy/smithy-client" "^4.9.8" + "@smithy/types" "^4.9.0" + "@smithy/url-parser" "^4.2.5" + "@smithy/util-base64" "^4.3.0" + "@smithy/util-body-length-browser" "^4.2.0" + "@smithy/util-body-length-node" "^4.2.1" + "@smithy/util-defaults-mode-browser" "^4.3.11" + "@smithy/util-defaults-mode-node" "^4.2.14" + "@smithy/util-endpoints" "^3.2.5" + "@smithy/util-middleware" "^4.2.5" + "@smithy/util-retry" "^4.2.5" + "@smithy/util-utf8" "^4.2.0" + tslib "^2.6.2" + +"@aws-sdk/region-config-resolver@3.936.0": + version "3.936.0" + resolved "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.936.0.tgz" + integrity sha512-wOKhzzWsshXGduxO4pqSiNyL9oUtk4BEvjWm9aaq6Hmfdoydq6v6t0rAGHWPjFwy9z2haovGRi3C8IxdMB4muw== + dependencies: + "@aws-sdk/types" "3.936.0" + "@smithy/config-resolver" "^4.4.3" + "@smithy/node-config-provider" "^4.3.5" + "@smithy/types" "^4.9.0" + tslib "^2.6.2" + +"@aws-sdk/signature-v4-multi-region@3.940.0": + version "3.940.0" + resolved "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.940.0.tgz" + integrity sha512-ugHZEoktD/bG6mdgmhzLDjMP2VrYRAUPRPF1DpCyiZexkH7DCU7XrSJyXMvkcf0DHV+URk0q2sLf/oqn1D2uYw== + dependencies: + "@aws-sdk/middleware-sdk-s3" "3.940.0" + "@aws-sdk/types" "3.936.0" + "@smithy/protocol-http" "^5.3.5" + "@smithy/signature-v4" "^5.3.5" + "@smithy/types" "^4.9.0" + tslib "^2.6.2" + +"@aws-sdk/token-providers@3.940.0": + version "3.940.0" + resolved "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.940.0.tgz" + integrity sha512-k5qbRe/ZFjW9oWEdzLIa2twRVIEx7p/9rutofyrRysrtEnYh3HAWCngAnwbgKMoiwa806UzcTRx0TjyEpnKcCg== + dependencies: + "@aws-sdk/core" "3.940.0" + "@aws-sdk/nested-clients" "3.940.0" + "@aws-sdk/types" "3.936.0" + "@smithy/property-provider" "^4.2.5" + "@smithy/shared-ini-file-loader" "^4.4.0" + "@smithy/types" "^4.9.0" + tslib "^2.6.2" + +"@aws-sdk/types@3.936.0", "@aws-sdk/types@^3.222.0": + version "3.936.0" + resolved "https://registry.npmjs.org/@aws-sdk/types/-/types-3.936.0.tgz" + integrity sha512-uz0/VlMd2pP5MepdrHizd+T+OKfyK4r3OA9JI+L/lPKg0YFQosdJNCKisr6o70E3dh8iMpFYxF1UN/4uZsyARg== + dependencies: + "@smithy/types" "^4.9.0" + tslib "^2.6.2" + +"@aws-sdk/util-arn-parser@3.893.0": + version "3.893.0" + resolved "https://registry.npmjs.org/@aws-sdk/util-arn-parser/-/util-arn-parser-3.893.0.tgz" + integrity sha512-u8H4f2Zsi19DGnwj5FSZzDMhytYF/bCh37vAtBsn3cNDL3YG578X5oc+wSX54pM3tOxS+NY7tvOAo52SW7koUA== + dependencies: + tslib "^2.6.2" + +"@aws-sdk/util-endpoints@3.936.0": + version "3.936.0" + resolved "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.936.0.tgz" + integrity sha512-0Zx3Ntdpu+z9Wlm7JKUBOzS9EunwKAb4KdGUQQxDqh5Lc3ta5uBoub+FgmVuzwnmBu9U1Os8UuwVTH0Lgu+P5w== + dependencies: + "@aws-sdk/types" "3.936.0" + "@smithy/types" "^4.9.0" + "@smithy/url-parser" "^4.2.5" + "@smithy/util-endpoints" "^3.2.5" + tslib "^2.6.2" + +"@aws-sdk/util-locate-window@^3.0.0": + version "3.893.0" + resolved "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.893.0.tgz" + integrity sha512-T89pFfgat6c8nMmpI8eKjBcDcgJq36+m9oiXbcUzeU55MP9ZuGgBomGjGnHaEyF36jenW9gmg3NfZDm0AO2XPg== + dependencies: + tslib "^2.6.2" + +"@aws-sdk/util-user-agent-browser@3.936.0": + version "3.936.0" + resolved "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.936.0.tgz" + integrity sha512-eZ/XF6NxMtu+iCma58GRNRxSq4lHo6zHQLOZRIeL/ghqYJirqHdenMOwrzPettj60KWlv827RVebP9oNVrwZbw== + dependencies: + "@aws-sdk/types" "3.936.0" + "@smithy/types" "^4.9.0" + bowser "^2.11.0" + tslib "^2.6.2" + +"@aws-sdk/util-user-agent-node@3.940.0": + version "3.940.0" + resolved "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.940.0.tgz" + integrity sha512-dlD/F+L/jN26I8Zg5x0oDGJiA+/WEQmnSE27fi5ydvYnpfQLwThtQo9SsNS47XSR/SOULaaoC9qx929rZuo74A== + dependencies: + "@aws-sdk/middleware-user-agent" "3.940.0" + "@aws-sdk/types" "3.936.0" + "@smithy/node-config-provider" "^4.3.5" + "@smithy/types" "^4.9.0" + tslib "^2.6.2" + +"@aws-sdk/xml-builder@3.930.0": + version "3.930.0" + resolved "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.930.0.tgz" + integrity sha512-YIfkD17GocxdmlUVc3ia52QhcWuRIUJonbF8A2CYfcWNV3HzvAqpcPeC0bYUhkK+8e8YO1ARnLKZQE0TlwzorA== + dependencies: + "@smithy/types" "^4.9.0" + fast-xml-parser "5.2.5" + tslib "^2.6.2" + +"@aws/lambda-invoke-store@^0.2.0": + version "0.2.2" + resolved "https://registry.npmjs.org/@aws/lambda-invoke-store/-/lambda-invoke-store-0.2.2.tgz" + integrity sha512-C0NBLsIqzDIae8HFw9YIrIBsbc0xTiOtt7fAukGPnqQ/+zZNaq+4jhuccltK0QuWHBnNm/a6kLIRA6GFiM10eg== + +"@biomejs/biome@2.3.8": + version "2.3.8" + resolved "https://registry.npmjs.org/@biomejs/biome/-/biome-2.3.8.tgz" + integrity sha512-Qjsgoe6FEBxWAUzwFGFrB+1+M8y/y5kwmg5CHac+GSVOdmOIqsAiXM5QMVGZJ1eCUCLlPZtq4aFAQ0eawEUuUA== + optionalDependencies: + "@biomejs/cli-darwin-arm64" "2.3.8" + "@biomejs/cli-darwin-x64" "2.3.8" + "@biomejs/cli-linux-arm64" "2.3.8" + "@biomejs/cli-linux-arm64-musl" "2.3.8" + "@biomejs/cli-linux-x64" "2.3.8" + "@biomejs/cli-linux-x64-musl" "2.3.8" + "@biomejs/cli-win32-arm64" "2.3.8" + "@biomejs/cli-win32-x64" "2.3.8" + +"@biomejs/cli-darwin-arm64@2.3.8": + version "2.3.8" + resolved "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.3.8.tgz" + integrity sha512-HM4Zg9CGQ3txTPflxD19n8MFPrmUAjaC7PQdLkugeeC0cQ+PiVrd7i09gaBS/11QKsTDBJhVg85CEIK9f50Qww== + +"@biomejs/cli-darwin-x64@2.3.8": + version "2.3.8" + resolved "https://registry.yarnpkg.com/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.3.8.tgz#5765d66ac9e92d80469ab5c24344ab6d3410ff75" + integrity sha512-lUDQ03D7y/qEao7RgdjWVGCu+BLYadhKTm40HkpJIi6kn8LSv5PAwRlew/DmwP4YZ9ke9XXoTIQDO1vAnbRZlA== + +"@biomejs/cli-linux-arm64-musl@2.3.8": + version "2.3.8" + resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.3.8.tgz#63ff811a3acc74c885e989a4e6e8f54399425e3a" + integrity sha512-PShR4mM0sjksUMyxbyPNMxoKFPVF48fU8Qe8Sfx6w6F42verbwRLbz+QiKNiDPRJwUoMG1nPM50OBL3aOnTevA== + +"@biomejs/cli-linux-arm64@2.3.8": + version "2.3.8" + resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.3.8.tgz#c6275cf8bc8592ef4ea840f5b1938606d3f3a721" + integrity sha512-Uo1OJnIkJgSgF+USx970fsM/drtPcQ39I+JO+Fjsaa9ZdCN1oysQmy6oAGbyESlouz+rzEckLTF6DS7cWse95g== + +"@biomejs/cli-linux-x64-musl@2.3.8": + version "2.3.8" + resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.3.8.tgz#95da386940356ef21d71d724587213915a6e7fef" + integrity sha512-YGLkqU91r1276uwSjiUD/xaVikdxgV1QpsicT0bIA1TaieM6E5ibMZeSyjQ/izBn4tKQthUSsVZacmoJfa3pDA== + +"@biomejs/cli-linux-x64@2.3.8": + version "2.3.8" + resolved "https://registry.yarnpkg.com/@biomejs/cli-linux-x64/-/cli-linux-x64-2.3.8.tgz#65fddc3feb27a6817763306b73506308cbdb1dcc" + integrity sha512-QDPMD5bQz6qOVb3kiBui0zKZXASLo0NIQ9JVJio5RveBEFgDgsvJFUvZIbMbUZT3T00M/1wdzwWXk4GIh0KaAw== + +"@biomejs/cli-win32-arm64@2.3.8": + version "2.3.8" + resolved "https://registry.yarnpkg.com/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.3.8.tgz#86385f8ff7abec220af11a7ddf9e57c39e317277" + integrity sha512-H4IoCHvL1fXKDrTALeTKMiE7GGWFAraDwBYFquE/L/5r1927Te0mYIGseXi4F+lrrwhSWbSGt5qPFswNoBaCxg== + +"@biomejs/cli-win32-x64@2.3.8": + version "2.3.8" + resolved "https://registry.yarnpkg.com/@biomejs/cli-win32-x64/-/cli-win32-x64-2.3.8.tgz#dca59fbf4c6f871f22f567ade203e996c7867206" + integrity sha512-RguzimPoZWtBapfKhKjcWXBVI91tiSprqdBYu7tWhgN8pKRZhw24rFeNZTNf6UiBfjCYCi9eFQs/JzJZIhuK4w== + +"@emnapi/core@^1.6.0", "@emnapi/core@^1.7.1": + version "1.7.1" + resolved "https://registry.yarnpkg.com/@emnapi/core/-/core-1.7.1.tgz#3a79a02dbc84f45884a1806ebb98e5746bdfaac4" + integrity sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg== + dependencies: + "@emnapi/wasi-threads" "1.1.0" + tslib "^2.4.0" + +"@emnapi/runtime@^1.6.0", "@emnapi/runtime@^1.7.0", "@emnapi/runtime@^1.7.1": + version "1.7.1" + resolved "https://registry.yarnpkg.com/@emnapi/runtime/-/runtime-1.7.1.tgz#a73784e23f5d57287369c808197288b52276b791" + integrity sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA== + dependencies: + tslib "^2.4.0" + +"@emnapi/wasi-threads@1.1.0", "@emnapi/wasi-threads@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz#60b2102fddc9ccb78607e4a3cf8403ea69be41bf" + integrity sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ== + dependencies: + tslib "^2.4.0" + +"@img/colour@^1.0.0": + version "1.0.0" + resolved "https://registry.npmjs.org/@img/colour/-/colour-1.0.0.tgz" + integrity sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw== + +"@img/sharp-darwin-arm64@0.34.5": + version "0.34.5" + resolved "https://registry.yarnpkg.com/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz#6e0732dcade126b6670af7aa17060b926835ea86" + integrity sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w== + optionalDependencies: + "@img/sharp-libvips-darwin-arm64" "1.2.4" + +"@img/sharp-darwin-x64@0.34.5": + version "0.34.5" + resolved "https://registry.yarnpkg.com/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz#19bc1dd6eba6d5a96283498b9c9f401180ee9c7b" + integrity sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw== + optionalDependencies: + "@img/sharp-libvips-darwin-x64" "1.2.4" + +"@img/sharp-libvips-darwin-arm64@1.2.4": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz#2894c0cb87d42276c3889942e8e2db517a492c43" + integrity sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g== + +"@img/sharp-libvips-darwin-x64@1.2.4": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz#e63681f4539a94af9cd17246ed8881734386f8cc" + integrity sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg== + +"@img/sharp-libvips-linux-arm64@1.2.4": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz#b1b288b36864b3bce545ad91fa6dadcf1a4ad318" + integrity sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw== + +"@img/sharp-libvips-linux-arm@1.2.4": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz#b9260dd1ebe6f9e3bdbcbdcac9d2ac125f35852d" + integrity sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A== + +"@img/sharp-libvips-linux-ppc64@1.2.4": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz#4b83ecf2a829057222b38848c7b022e7b4d07aa7" + integrity sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA== + +"@img/sharp-libvips-linux-riscv64@1.2.4": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz#880b4678009e5a2080af192332b00b0aaf8a48de" + integrity sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA== + +"@img/sharp-libvips-linux-s390x@1.2.4": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz#74f343c8e10fad821b38f75ced30488939dc59ec" + integrity sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ== + +"@img/sharp-libvips-linux-x64@1.2.4": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz#df4183e8bd8410f7d61b66859a35edeab0a531ce" + integrity sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw== + +"@img/sharp-libvips-linuxmusl-arm64@1.2.4": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz#c8d6b48211df67137541007ee8d1b7b1f8ca8e06" + integrity sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw== + +"@img/sharp-libvips-linuxmusl-x64@1.2.4": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz#be11c75bee5b080cbee31a153a8779448f919f75" + integrity sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg== + +"@img/sharp-linux-arm64@0.34.5": + version "0.34.5" + resolved "https://registry.yarnpkg.com/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz#7aa7764ef9c001f15e610546d42fce56911790cc" + integrity sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg== + optionalDependencies: + "@img/sharp-libvips-linux-arm64" "1.2.4" + +"@img/sharp-linux-arm@0.34.5": + version "0.34.5" + resolved "https://registry.yarnpkg.com/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz#5fb0c3695dd12522d39c3ff7a6bc816461780a0d" + integrity sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw== + optionalDependencies: + "@img/sharp-libvips-linux-arm" "1.2.4" + +"@img/sharp-linux-ppc64@0.34.5": + version "0.34.5" + resolved "https://registry.yarnpkg.com/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz#9c213a81520a20caf66978f3d4c07456ff2e0813" + integrity sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA== + optionalDependencies: + "@img/sharp-libvips-linux-ppc64" "1.2.4" + +"@img/sharp-linux-riscv64@0.34.5": + version "0.34.5" + resolved "https://registry.yarnpkg.com/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz#cdd28182774eadbe04f62675a16aabbccb833f60" + integrity sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw== + optionalDependencies: + "@img/sharp-libvips-linux-riscv64" "1.2.4" + +"@img/sharp-linux-s390x@0.34.5": + version "0.34.5" + resolved "https://registry.yarnpkg.com/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz#93eac601b9f329bb27917e0e19098c722d630df7" + integrity sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg== + optionalDependencies: + "@img/sharp-libvips-linux-s390x" "1.2.4" + +"@img/sharp-linux-x64@0.34.5": + version "0.34.5" + resolved "https://registry.yarnpkg.com/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz#55abc7cd754ffca5002b6c2b719abdfc846819a8" + integrity sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ== + optionalDependencies: + "@img/sharp-libvips-linux-x64" "1.2.4" + +"@img/sharp-linuxmusl-arm64@0.34.5": + version "0.34.5" + resolved "https://registry.yarnpkg.com/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz#d6515ee971bb62f73001a4829b9d865a11b77086" + integrity sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg== + optionalDependencies: + "@img/sharp-libvips-linuxmusl-arm64" "1.2.4" + +"@img/sharp-linuxmusl-x64@0.34.5": + version "0.34.5" + resolved "https://registry.yarnpkg.com/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz#d97978aec7c5212f999714f2f5b736457e12ee9f" + integrity sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q== + optionalDependencies: + "@img/sharp-libvips-linuxmusl-x64" "1.2.4" + +"@img/sharp-wasm32@0.34.5": + version "0.34.5" + resolved "https://registry.yarnpkg.com/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz#2f15803aa626f8c59dd7c9d0bbc766f1ab52cfa0" + integrity sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw== + dependencies: + "@emnapi/runtime" "^1.7.0" + +"@img/sharp-win32-arm64@0.34.5": + version "0.34.5" + resolved "https://registry.yarnpkg.com/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz#3706e9e3ac35fddfc1c87f94e849f1b75307ce0a" + integrity sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g== + +"@img/sharp-win32-ia32@0.34.5": + version "0.34.5" + resolved "https://registry.yarnpkg.com/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz#0b71166599b049e032f085fb9263e02f4e4788de" + integrity sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg== + +"@img/sharp-win32-x64@0.34.5": + version "0.34.5" + resolved "https://registry.yarnpkg.com/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz#a81ffb00e69267cd0a1d626eaedb8a8430b2b2f8" + integrity sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw== + +"@jridgewell/gen-mapping@^0.3.5": + version "0.3.13" + resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz" + integrity sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA== + dependencies: + "@jridgewell/sourcemap-codec" "^1.5.0" + "@jridgewell/trace-mapping" "^0.3.24" + +"@jridgewell/remapping@^2.3.4": + version "2.3.5" + resolved "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz" + integrity sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ== + dependencies: + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.24" + +"@jridgewell/resolve-uri@^3.1.0": + version "3.1.2" + resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz" + integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== + +"@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.5.0", "@jridgewell/sourcemap-codec@^1.5.5": + version "1.5.5" + resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz" + integrity sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og== + +"@jridgewell/trace-mapping@^0.3.24": + version "0.3.31" + resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz" + integrity sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + +"@napi-rs/wasm-runtime@^1.0.7": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.0.tgz#c0180393d7862cff0d412e3e1a7c3bd5ea6d9b2f" + integrity sha512-Fq6DJW+Bb5jaWE69/qOE0D1TUN9+6uWhCeZpdnSBk14pjLcCWR7Q8n49PTSPHazM37JqrsdpEthXy2xn6jWWiA== + dependencies: + "@emnapi/core" "^1.7.1" + "@emnapi/runtime" "^1.7.1" + "@tybys/wasm-util" "^0.10.1" + +"@next/env@16.0.7": + version "16.0.7" + resolved "https://registry.npmjs.org/@next/env/-/env-16.0.7.tgz" + integrity sha512-gpaNgUh5nftFKRkRQGnVi5dpcYSKGcZZkQffZ172OrG/XkrnS7UBTQ648YY+8ME92cC4IojpI2LqTC8sTDhAaw== + +"@next/swc-darwin-arm64@16.0.7": + version "16.0.7" + resolved "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.0.7.tgz" + integrity sha512-LlDtCYOEj/rfSnEn/Idi+j1QKHxY9BJFmxx7108A6D8K0SB+bNgfYQATPk/4LqOl4C0Wo3LACg2ie6s7xqMpJg== + +"@next/swc-darwin-x64@16.0.7": + version "16.0.7" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-16.0.7.tgz#ec5fd15ae391e1af9f152881f559bffaa24524e7" + integrity sha512-rtZ7BhnVvO1ICf3QzfW9H3aPz7GhBrnSIMZyr4Qy6boXF0b5E3QLs+cvJmg3PsTCG2M1PBoC+DANUi4wCOKXpA== + +"@next/swc-linux-arm64-gnu@16.0.7": + version "16.0.7" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.0.7.tgz#22be26ee7544f68aa916159b823899b67b09f0a6" + integrity sha512-mloD5WcPIeIeeZqAIP5c2kdaTa6StwP4/2EGy1mUw8HiexSHGK/jcM7lFuS3u3i2zn+xH9+wXJs6njO7VrAqww== + +"@next/swc-linux-arm64-musl@16.0.7": + version "16.0.7" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.0.7.tgz#1b34103951456e5d6766710e4f16dadbd7745bed" + integrity sha512-+ksWNrZrthisXuo9gd1XnjHRowCbMtl/YgMpbRvFeDEqEBd523YHPWpBuDjomod88U8Xliw5DHhekBC3EOOd9g== + +"@next/swc-linux-x64-gnu@16.0.7": + version "16.0.7" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.0.7.tgz#b45e1fa7aaf844269e0932c4cde49bb6b0817ce9" + integrity sha512-4WtJU5cRDxpEE44Ana2Xro1284hnyVpBb62lIpU5k85D8xXxatT+rXxBgPkc7C1XwkZMWpK5rXLXTh9PFipWsA== + +"@next/swc-linux-x64-musl@16.0.7": + version "16.0.7" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.0.7.tgz#c5376fd78ca97a911e2bbfb9b26dc623b54edfab" + integrity sha512-HYlhqIP6kBPXalW2dbMTSuB4+8fe+j9juyxwfMwCe9kQPPeiyFn7NMjNfoFOfJ2eXkeQsoUGXg+O2SE3m4Qg2w== + +"@next/swc-win32-arm64-msvc@16.0.7": + version "16.0.7" + resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.0.7.tgz#2cf27e275ddd8d04f89391a9cdf6790cccb3bf09" + integrity sha512-EviG+43iOoBRZg9deGauXExjRphhuYmIOJ12b9sAPy0eQ6iwcPxfED2asb/s2/yiLYOdm37kPaiZu8uXSYPs0Q== + +"@next/swc-win32-x64-msvc@16.0.7": + version "16.0.7" + resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.0.7.tgz#e9e38fcca752902542c25c527e532af71e9ca812" + integrity sha512-gniPjy55zp5Eg0896qSrf3yB1dw4F/3s8VK1ephdsZZ129j2n6e1WqCbE2YgcKhW9hPB9TVZENugquWJD5x0ug== + +"@noble/ciphers@^1.3.0": + version "1.3.0" + resolved "https://registry.npmjs.org/@noble/ciphers/-/ciphers-1.3.0.tgz" + integrity sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw== + +"@noble/curves@1.9.1", "@noble/curves@~1.9.0": + version "1.9.1" + resolved "https://registry.npmjs.org/@noble/curves/-/curves-1.9.1.tgz" + integrity sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA== + dependencies: + "@noble/hashes" "1.8.0" + +"@noble/hashes@1.8.0", "@noble/hashes@^1.8.0", "@noble/hashes@~1.8.0": + version "1.8.0" + resolved "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz" + integrity sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A== + +"@scure/base@~1.2.5": + version "1.2.6" + resolved "https://registry.npmjs.org/@scure/base/-/base-1.2.6.tgz" + integrity sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg== + +"@scure/bip32@1.7.0", "@scure/bip32@^1.7.0": + version "1.7.0" + resolved "https://registry.npmjs.org/@scure/bip32/-/bip32-1.7.0.tgz" + integrity sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw== + dependencies: + "@noble/curves" "~1.9.0" + "@noble/hashes" "~1.8.0" + "@scure/base" "~1.2.5" + +"@scure/bip39@1.6.0", "@scure/bip39@^1.6.0": + version "1.6.0" + resolved "https://registry.npmjs.org/@scure/bip39/-/bip39-1.6.0.tgz" + integrity sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A== + dependencies: + "@noble/hashes" "~1.8.0" + "@scure/base" "~1.2.5" + +"@smithy/abort-controller@^4.2.5": + version "4.2.5" + resolved "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-4.2.5.tgz" + integrity sha512-j7HwVkBw68YW8UmFRcjZOmssE77Rvk0GWAIN1oFBhsaovQmZWYCIcGa9/pwRB0ExI8Sk9MWNALTjftjHZea7VA== + dependencies: + "@smithy/types" "^4.9.0" + tslib "^2.6.2" + +"@smithy/chunked-blob-reader-native@^4.2.1": + version "4.2.1" + resolved "https://registry.npmjs.org/@smithy/chunked-blob-reader-native/-/chunked-blob-reader-native-4.2.1.tgz" + integrity sha512-lX9Ay+6LisTfpLid2zZtIhSEjHMZoAR5hHCR4H7tBz/Zkfr5ea8RcQ7Tk4mi0P76p4cN+Btz16Ffno7YHpKXnQ== + dependencies: + "@smithy/util-base64" "^4.3.0" + tslib "^2.6.2" + +"@smithy/chunked-blob-reader@^5.2.0": + version "5.2.0" + resolved "https://registry.npmjs.org/@smithy/chunked-blob-reader/-/chunked-blob-reader-5.2.0.tgz" + integrity sha512-WmU0TnhEAJLWvfSeMxBNe5xtbselEO8+4wG0NtZeL8oR21WgH1xiO37El+/Y+H/Ie4SCwBy3MxYWmOYaGgZueA== + dependencies: + tslib "^2.6.2" + +"@smithy/config-resolver@^4.4.3": + version "4.4.3" + resolved "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-4.4.3.tgz" + integrity sha512-ezHLe1tKLUxDJo2LHtDuEDyWXolw8WGOR92qb4bQdWq/zKenO5BvctZGrVJBK08zjezSk7bmbKFOXIVyChvDLw== + dependencies: + "@smithy/node-config-provider" "^4.3.5" + "@smithy/types" "^4.9.0" + "@smithy/util-config-provider" "^4.2.0" + "@smithy/util-endpoints" "^3.2.5" + "@smithy/util-middleware" "^4.2.5" + tslib "^2.6.2" + +"@smithy/core@^3.18.5", "@smithy/core@^3.18.6": + version "3.18.6" + resolved "https://registry.npmjs.org/@smithy/core/-/core-3.18.6.tgz" + integrity sha512-8Q/ugWqfDUEU1Exw71+DoOzlONJ2Cn9QA8VeeDzLLjzO/qruh9UKFzbszy4jXcIYgGofxYiT0t1TT6+CT/GupQ== + dependencies: + "@smithy/middleware-serde" "^4.2.6" + "@smithy/protocol-http" "^5.3.5" + "@smithy/types" "^4.9.0" + "@smithy/util-base64" "^4.3.0" + "@smithy/util-body-length-browser" "^4.2.0" + "@smithy/util-middleware" "^4.2.5" + "@smithy/util-stream" "^4.5.6" + "@smithy/util-utf8" "^4.2.0" + "@smithy/uuid" "^1.1.0" + tslib "^2.6.2" + +"@smithy/credential-provider-imds@^4.2.5": + version "4.2.5" + resolved "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.2.5.tgz" + integrity sha512-BZwotjoZWn9+36nimwm/OLIcVe+KYRwzMjfhd4QT7QxPm9WY0HiOV8t/Wlh+HVUif0SBVV7ksq8//hPaBC/okQ== + dependencies: + "@smithy/node-config-provider" "^4.3.5" + "@smithy/property-provider" "^4.2.5" + "@smithy/types" "^4.9.0" + "@smithy/url-parser" "^4.2.5" + tslib "^2.6.2" + +"@smithy/eventstream-codec@^4.2.5": + version "4.2.5" + resolved "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-4.2.5.tgz" + integrity sha512-Ogt4Zi9hEbIP17oQMd68qYOHUzmH47UkK7q7Gl55iIm9oKt27MUGrC5JfpMroeHjdkOliOA4Qt3NQ1xMq/nrlA== + dependencies: + "@aws-crypto/crc32" "5.2.0" + "@smithy/types" "^4.9.0" + "@smithy/util-hex-encoding" "^4.2.0" + tslib "^2.6.2" + +"@smithy/eventstream-serde-browser@^4.2.5": + version "4.2.5" + resolved "https://registry.npmjs.org/@smithy/eventstream-serde-browser/-/eventstream-serde-browser-4.2.5.tgz" + integrity sha512-HohfmCQZjppVnKX2PnXlf47CW3j92Ki6T/vkAT2DhBR47e89pen3s4fIa7otGTtrVxmj7q+IhH0RnC5kpR8wtw== + dependencies: + "@smithy/eventstream-serde-universal" "^4.2.5" + "@smithy/types" "^4.9.0" + tslib "^2.6.2" + +"@smithy/eventstream-serde-config-resolver@^4.3.5": + version "4.3.5" + resolved "https://registry.npmjs.org/@smithy/eventstream-serde-config-resolver/-/eventstream-serde-config-resolver-4.3.5.tgz" + integrity sha512-ibjQjM7wEXtECiT6my1xfiMH9IcEczMOS6xiCQXoUIYSj5b1CpBbJ3VYbdwDy8Vcg5JHN7eFpOCGk8nyZAltNQ== + dependencies: + "@smithy/types" "^4.9.0" + tslib "^2.6.2" + +"@smithy/eventstream-serde-node@^4.2.5": + version "4.2.5" + resolved "https://registry.npmjs.org/@smithy/eventstream-serde-node/-/eventstream-serde-node-4.2.5.tgz" + integrity sha512-+elOuaYx6F2H6x1/5BQP5ugv12nfJl66GhxON8+dWVUEDJ9jah/A0tayVdkLRP0AeSac0inYkDz5qBFKfVp2Gg== + dependencies: + "@smithy/eventstream-serde-universal" "^4.2.5" + "@smithy/types" "^4.9.0" + tslib "^2.6.2" + +"@smithy/eventstream-serde-universal@^4.2.5": + version "4.2.5" + resolved "https://registry.npmjs.org/@smithy/eventstream-serde-universal/-/eventstream-serde-universal-4.2.5.tgz" + integrity sha512-G9WSqbST45bmIFaeNuP/EnC19Rhp54CcVdX9PDL1zyEB514WsDVXhlyihKlGXnRycmHNmVv88Bvvt4EYxWef/Q== + dependencies: + "@smithy/eventstream-codec" "^4.2.5" + "@smithy/types" "^4.9.0" + tslib "^2.6.2" + +"@smithy/fetch-http-handler@^5.3.6": + version "5.3.6" + resolved "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.3.6.tgz" + integrity sha512-3+RG3EA6BBJ/ofZUeTFJA7mHfSYrZtQIrDP9dI8Lf7X6Jbos2jptuLrAAteDiFVrmbEmLSuRG/bUKzfAXk7dhg== + dependencies: + "@smithy/protocol-http" "^5.3.5" + "@smithy/querystring-builder" "^4.2.5" + "@smithy/types" "^4.9.0" + "@smithy/util-base64" "^4.3.0" + tslib "^2.6.2" + +"@smithy/hash-blob-browser@^4.2.6": + version "4.2.6" + resolved "https://registry.npmjs.org/@smithy/hash-blob-browser/-/hash-blob-browser-4.2.6.tgz" + integrity sha512-8P//tA8DVPk+3XURk2rwcKgYwFvwGwmJH/wJqQiSKwXZtf/LiZK+hbUZmPj/9KzM+OVSwe4o85KTp5x9DUZTjw== + dependencies: + "@smithy/chunked-blob-reader" "^5.2.0" + "@smithy/chunked-blob-reader-native" "^4.2.1" + "@smithy/types" "^4.9.0" + tslib "^2.6.2" + +"@smithy/hash-node@^4.2.5": + version "4.2.5" + resolved "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-4.2.5.tgz" + integrity sha512-DpYX914YOfA3UDT9CN1BM787PcHfWRBB43fFGCYrZFUH0Jv+5t8yYl+Pd5PW4+QzoGEDvn5d5QIO4j2HyYZQSA== + dependencies: + "@smithy/types" "^4.9.0" + "@smithy/util-buffer-from" "^4.2.0" + "@smithy/util-utf8" "^4.2.0" + tslib "^2.6.2" + +"@smithy/hash-stream-node@^4.2.5": + version "4.2.5" + resolved "https://registry.npmjs.org/@smithy/hash-stream-node/-/hash-stream-node-4.2.5.tgz" + integrity sha512-6+do24VnEyvWcGdHXomlpd0m8bfZePpUKBy7m311n+JuRwug8J4dCanJdTymx//8mi0nlkflZBvJe+dEO/O12Q== + dependencies: + "@smithy/types" "^4.9.0" + "@smithy/util-utf8" "^4.2.0" + tslib "^2.6.2" + +"@smithy/invalid-dependency@^4.2.5": + version "4.2.5" + resolved "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-4.2.5.tgz" + integrity sha512-2L2erASEro1WC5nV+plwIMxrTXpvpfzl4e+Nre6vBVRR2HKeGGcvpJyyL3/PpiSg+cJG2KpTmZmq934Olb6e5A== + dependencies: + "@smithy/types" "^4.9.0" + tslib "^2.6.2" + +"@smithy/is-array-buffer@^2.2.0": + version "2.2.0" + resolved "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz" + integrity sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA== + dependencies: + tslib "^2.6.2" + +"@smithy/is-array-buffer@^4.2.0": + version "4.2.0" + resolved "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-4.2.0.tgz" + integrity sha512-DZZZBvC7sjcYh4MazJSGiWMI2L7E0oCiRHREDzIxi/M2LY79/21iXt6aPLHge82wi5LsuRF5A06Ds3+0mlh6CQ== + dependencies: + tslib "^2.6.2" + +"@smithy/md5-js@^4.2.5": + version "4.2.5" + resolved "https://registry.npmjs.org/@smithy/md5-js/-/md5-js-4.2.5.tgz" + integrity sha512-Bt6jpSTMWfjCtC0s79gZ/WZ1w90grfmopVOWqkI2ovhjpD5Q2XRXuecIPB9689L2+cCySMbaXDhBPU56FKNDNg== + dependencies: + "@smithy/types" "^4.9.0" + "@smithy/util-utf8" "^4.2.0" + tslib "^2.6.2" + +"@smithy/middleware-content-length@^4.2.5": + version "4.2.5" + resolved "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-4.2.5.tgz" + integrity sha512-Y/RabVa5vbl5FuHYV2vUCwvh/dqzrEY/K2yWPSqvhFUwIY0atLqO4TienjBXakoy4zrKAMCZwg+YEqmH7jaN7A== + dependencies: + "@smithy/protocol-http" "^5.3.5" + "@smithy/types" "^4.9.0" + tslib "^2.6.2" + +"@smithy/middleware-endpoint@^4.3.12", "@smithy/middleware-endpoint@^4.3.13": + version "4.3.13" + resolved "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.3.13.tgz" + integrity sha512-X4za1qCdyx1hEVVXuAWlZuK6wzLDv1uw1OY9VtaYy1lULl661+frY7FeuHdYdl7qAARUxH2yvNExU2/SmRFfcg== + dependencies: + "@smithy/core" "^3.18.6" + "@smithy/middleware-serde" "^4.2.6" + "@smithy/node-config-provider" "^4.3.5" + "@smithy/shared-ini-file-loader" "^4.4.0" + "@smithy/types" "^4.9.0" + "@smithy/url-parser" "^4.2.5" + "@smithy/util-middleware" "^4.2.5" + tslib "^2.6.2" + +"@smithy/middleware-retry@^4.4.12": + version "4.4.13" + resolved "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.4.13.tgz" + integrity sha512-RzIDF9OrSviXX7MQeKOm8r/372KTyY8Jmp6HNKOOYlrguHADuM3ED/f4aCyNhZZFLG55lv5beBin7nL0Nzy1Dw== + dependencies: + "@smithy/node-config-provider" "^4.3.5" + "@smithy/protocol-http" "^5.3.5" + "@smithy/service-error-classification" "^4.2.5" + "@smithy/smithy-client" "^4.9.9" + "@smithy/types" "^4.9.0" + "@smithy/util-middleware" "^4.2.5" + "@smithy/util-retry" "^4.2.5" + "@smithy/uuid" "^1.1.0" + tslib "^2.6.2" + +"@smithy/middleware-serde@^4.2.6": + version "4.2.6" + resolved "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-4.2.6.tgz" + integrity sha512-VkLoE/z7e2g8pirwisLz8XJWedUSY8my/qrp81VmAdyrhi94T+riBfwP+AOEEFR9rFTSonC/5D2eWNmFabHyGQ== + dependencies: + "@smithy/protocol-http" "^5.3.5" + "@smithy/types" "^4.9.0" + tslib "^2.6.2" + +"@smithy/middleware-stack@^4.2.5": + version "4.2.5" + resolved "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-4.2.5.tgz" + integrity sha512-bYrutc+neOyWxtZdbB2USbQttZN0mXaOyYLIsaTbJhFsfpXyGWUxJpEuO1rJ8IIJm2qH4+xJT0mxUSsEDTYwdQ== + dependencies: + "@smithy/types" "^4.9.0" + tslib "^2.6.2" + +"@smithy/node-config-provider@^4.3.5": + version "4.3.5" + resolved "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-4.3.5.tgz" + integrity sha512-UTurh1C4qkVCtqggI36DGbLB2Kv8UlcFdMXDcWMbqVY2uRg0XmT9Pb4Vj6oSQ34eizO1fvR0RnFV4Axw4IrrAg== + dependencies: + "@smithy/property-provider" "^4.2.5" + "@smithy/shared-ini-file-loader" "^4.4.0" + "@smithy/types" "^4.9.0" + tslib "^2.6.2" + +"@smithy/node-http-handler@^4.4.5": + version "4.4.5" + resolved "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.4.5.tgz" + integrity sha512-CMnzM9R2WqlqXQGtIlsHMEZfXKJVTIrqCNoSd/QpAyp+Dw0a1Vps13l6ma1fH8g7zSPNsA59B/kWgeylFuA/lw== + dependencies: + "@smithy/abort-controller" "^4.2.5" + "@smithy/protocol-http" "^5.3.5" + "@smithy/querystring-builder" "^4.2.5" + "@smithy/types" "^4.9.0" + tslib "^2.6.2" + +"@smithy/property-provider@^4.2.5": + version "4.2.5" + resolved "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-4.2.5.tgz" + integrity sha512-8iLN1XSE1rl4MuxvQ+5OSk/Zb5El7NJZ1td6Tn+8dQQHIjp59Lwl6bd0+nzw6SKm2wSSriH2v/I9LPzUic7EOg== + dependencies: + "@smithy/types" "^4.9.0" + tslib "^2.6.2" + +"@smithy/protocol-http@^5.3.5": + version "5.3.5" + resolved "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-5.3.5.tgz" + integrity sha512-RlaL+sA0LNMp03bf7XPbFmT5gN+w3besXSWMkA8rcmxLSVfiEXElQi4O2IWwPfxzcHkxqrwBFMbngB8yx/RvaQ== + dependencies: + "@smithy/types" "^4.9.0" + tslib "^2.6.2" + +"@smithy/querystring-builder@^4.2.5": + version "4.2.5" + resolved "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-4.2.5.tgz" + integrity sha512-y98otMI1saoajeik2kLfGyRp11e5U/iJYH/wLCh3aTV/XutbGT9nziKGkgCaMD1ghK7p6htHMm6b6scl9JRUWg== + dependencies: + "@smithy/types" "^4.9.0" + "@smithy/util-uri-escape" "^4.2.0" + tslib "^2.6.2" + +"@smithy/querystring-parser@^4.2.5": + version "4.2.5" + resolved "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-4.2.5.tgz" + integrity sha512-031WCTdPYgiQRYNPXznHXof2YM0GwL6SeaSyTH/P72M1Vz73TvCNH2Nq8Iu2IEPq9QP2yx0/nrw5YmSeAi/AjQ== + dependencies: + "@smithy/types" "^4.9.0" + tslib "^2.6.2" + +"@smithy/service-error-classification@^4.2.5": + version "4.2.5" + resolved "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-4.2.5.tgz" + integrity sha512-8fEvK+WPE3wUAcDvqDQG1Vk3ANLR8Px979te96m84CbKAjBVf25rPYSzb4xU4hlTyho7VhOGnh5i62D/JVF0JQ== + dependencies: + "@smithy/types" "^4.9.0" + +"@smithy/shared-ini-file-loader@^4.4.0": + version "4.4.0" + resolved "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-4.4.0.tgz" + integrity sha512-5WmZ5+kJgJDjwXXIzr1vDTG+RhF9wzSODQBfkrQ2VVkYALKGvZX1lgVSxEkgicSAFnFhPj5rudJV0zoinqS0bA== + dependencies: + "@smithy/types" "^4.9.0" + tslib "^2.6.2" + +"@smithy/signature-v4@^5.3.5": + version "5.3.5" + resolved "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.3.5.tgz" + integrity sha512-xSUfMu1FT7ccfSXkoLl/QRQBi2rOvi3tiBZU2Tdy3I6cgvZ6SEi9QNey+lqps/sJRnogIS+lq+B1gxxbra2a/w== + dependencies: + "@smithy/is-array-buffer" "^4.2.0" + "@smithy/protocol-http" "^5.3.5" + "@smithy/types" "^4.9.0" + "@smithy/util-hex-encoding" "^4.2.0" + "@smithy/util-middleware" "^4.2.5" + "@smithy/util-uri-escape" "^4.2.0" + "@smithy/util-utf8" "^4.2.0" + tslib "^2.6.2" + +"@smithy/smithy-client@^4.9.8", "@smithy/smithy-client@^4.9.9": + version "4.9.9" + resolved "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.9.9.tgz" + integrity sha512-SUnZJMMo5yCmgjopJbiNeo1vlr8KvdnEfIHV9rlD77QuOGdRotIVBcOrBuMr+sI9zrnhtDtLP054bZVbpZpiQA== + dependencies: + "@smithy/core" "^3.18.6" + "@smithy/middleware-endpoint" "^4.3.13" + "@smithy/middleware-stack" "^4.2.5" + "@smithy/protocol-http" "^5.3.5" + "@smithy/types" "^4.9.0" + "@smithy/util-stream" "^4.5.6" + tslib "^2.6.2" + +"@smithy/types@^4.9.0": + version "4.9.0" + resolved "https://registry.npmjs.org/@smithy/types/-/types-4.9.0.tgz" + integrity sha512-MvUbdnXDTwykR8cB1WZvNNwqoWVaTRA0RLlLmf/cIFNMM2cKWz01X4Ly6SMC4Kks30r8tT3Cty0jmeWfiuyHTA== + dependencies: + tslib "^2.6.2" + +"@smithy/url-parser@^4.2.5": + version "4.2.5" + resolved "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-4.2.5.tgz" + integrity sha512-VaxMGsilqFnK1CeBX+LXnSuaMx4sTL/6znSZh2829txWieazdVxr54HmiyTsIbpOTLcf5nYpq9lpzmwRdxj6rQ== + dependencies: + "@smithy/querystring-parser" "^4.2.5" + "@smithy/types" "^4.9.0" + tslib "^2.6.2" + +"@smithy/util-base64@^4.3.0": + version "4.3.0" + resolved "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-4.3.0.tgz" + integrity sha512-GkXZ59JfyxsIwNTWFnjmFEI8kZpRNIBfxKjv09+nkAWPt/4aGaEWMM04m4sxgNVWkbt2MdSvE3KF/PfX4nFedQ== + dependencies: + "@smithy/util-buffer-from" "^4.2.0" + "@smithy/util-utf8" "^4.2.0" + tslib "^2.6.2" + +"@smithy/util-body-length-browser@^4.2.0": + version "4.2.0" + resolved "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-4.2.0.tgz" + integrity sha512-Fkoh/I76szMKJnBXWPdFkQJl2r9SjPt3cMzLdOB6eJ4Pnpas8hVoWPYemX/peO0yrrvldgCUVJqOAjUrOLjbxg== + dependencies: + tslib "^2.6.2" + +"@smithy/util-body-length-node@^4.2.1": + version "4.2.1" + resolved "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-4.2.1.tgz" + integrity sha512-h53dz/pISVrVrfxV1iqXlx5pRg3V2YWFcSQyPyXZRrZoZj4R4DeWRDo1a7dd3CPTcFi3kE+98tuNyD2axyZReA== + dependencies: + tslib "^2.6.2" + +"@smithy/util-buffer-from@^2.2.0": + version "2.2.0" + resolved "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz" + integrity sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA== + dependencies: + "@smithy/is-array-buffer" "^2.2.0" + tslib "^2.6.2" + +"@smithy/util-buffer-from@^4.2.0": + version "4.2.0" + resolved "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-4.2.0.tgz" + integrity sha512-kAY9hTKulTNevM2nlRtxAG2FQ3B2OR6QIrPY3zE5LqJy1oxzmgBGsHLWTcNhWXKchgA0WHW+mZkQrng/pgcCew== + dependencies: + "@smithy/is-array-buffer" "^4.2.0" + tslib "^2.6.2" + +"@smithy/util-config-provider@^4.2.0": + version "4.2.0" + resolved "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-4.2.0.tgz" + integrity sha512-YEjpl6XJ36FTKmD+kRJJWYvrHeUvm5ykaUS5xK+6oXffQPHeEM4/nXlZPe+Wu0lsgRUcNZiliYNh/y7q9c2y6Q== + dependencies: + tslib "^2.6.2" + +"@smithy/util-defaults-mode-browser@^4.3.11": + version "4.3.12" + resolved "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.3.12.tgz" + integrity sha512-TKc6FnOxFULKxLgTNHYjcFqdOYzXVPFFVm5JhI30F3RdhT7nYOtOsjgaOwfDRmA/3U66O9KaBQ3UHoXwayRhAg== + dependencies: + "@smithy/property-provider" "^4.2.5" + "@smithy/smithy-client" "^4.9.9" + "@smithy/types" "^4.9.0" + tslib "^2.6.2" + +"@smithy/util-defaults-mode-node@^4.2.14": + version "4.2.15" + resolved "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.2.15.tgz" + integrity sha512-94NqfQVo+vGc5gsQ9SROZqOvBkGNMQu6pjXbnn8aQvBUhc31kx49gxlkBEqgmaZQHUUfdRUin5gK/HlHKmbAwg== + dependencies: + "@smithy/config-resolver" "^4.4.3" + "@smithy/credential-provider-imds" "^4.2.5" + "@smithy/node-config-provider" "^4.3.5" + "@smithy/property-provider" "^4.2.5" + "@smithy/smithy-client" "^4.9.9" + "@smithy/types" "^4.9.0" + tslib "^2.6.2" + +"@smithy/util-endpoints@^3.2.5": + version "3.2.5" + resolved "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-3.2.5.tgz" + integrity sha512-3O63AAWu2cSNQZp+ayl9I3NapW1p1rR5mlVHcF6hAB1dPZUQFfRPYtplWX/3xrzWthPGj5FqB12taJJCfH6s8A== + dependencies: + "@smithy/node-config-provider" "^4.3.5" + "@smithy/types" "^4.9.0" + tslib "^2.6.2" + +"@smithy/util-hex-encoding@^4.2.0": + version "4.2.0" + resolved "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-4.2.0.tgz" + integrity sha512-CCQBwJIvXMLKxVbO88IukazJD9a4kQ9ZN7/UMGBjBcJYvatpWk+9g870El4cB8/EJxfe+k+y0GmR9CAzkF+Nbw== + dependencies: + tslib "^2.6.2" + +"@smithy/util-middleware@^4.2.5": + version "4.2.5" + resolved "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-4.2.5.tgz" + integrity sha512-6Y3+rvBF7+PZOc40ybeZMcGln6xJGVeY60E7jy9Mv5iKpMJpHgRE6dKy9ScsVxvfAYuEX4Q9a65DQX90KaQ3bA== + dependencies: + "@smithy/types" "^4.9.0" + tslib "^2.6.2" + +"@smithy/util-retry@^4.2.5": + version "4.2.5" + resolved "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-4.2.5.tgz" + integrity sha512-GBj3+EZBbN4NAqJ/7pAhsXdfzdlznOh8PydUijy6FpNIMnHPSMO2/rP4HKu+UFeikJxShERk528oy7GT79YiJg== + dependencies: + "@smithy/service-error-classification" "^4.2.5" + "@smithy/types" "^4.9.0" + tslib "^2.6.2" + +"@smithy/util-stream@^4.5.6": + version "4.5.6" + resolved "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-4.5.6.tgz" + integrity sha512-qWw/UM59TiaFrPevefOZ8CNBKbYEP6wBAIlLqxn3VAIo9rgnTNc4ASbVrqDmhuwI87usnjhdQrxodzAGFFzbRQ== + dependencies: + "@smithy/fetch-http-handler" "^5.3.6" + "@smithy/node-http-handler" "^4.4.5" + "@smithy/types" "^4.9.0" + "@smithy/util-base64" "^4.3.0" + "@smithy/util-buffer-from" "^4.2.0" + "@smithy/util-hex-encoding" "^4.2.0" + "@smithy/util-utf8" "^4.2.0" + tslib "^2.6.2" + +"@smithy/util-uri-escape@^4.2.0": + version "4.2.0" + resolved "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-4.2.0.tgz" + integrity sha512-igZpCKV9+E/Mzrpq6YacdTQ0qTiLm85gD6N/IrmyDvQFA4UnU3d5g3m8tMT/6zG/vVkWSU+VxeUyGonL62DuxA== + dependencies: + tslib "^2.6.2" + +"@smithy/util-utf8@^2.0.0": + version "2.3.0" + resolved "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz" + integrity sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A== + dependencies: + "@smithy/util-buffer-from" "^2.2.0" + tslib "^2.6.2" + +"@smithy/util-utf8@^4.2.0": + version "4.2.0" + resolved "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-4.2.0.tgz" + integrity sha512-zBPfuzoI8xyBtR2P6WQj63Rz8i3AmfAaJLuNG8dWsfvPe8lO4aCPYLn879mEgHndZH1zQ2oXmG8O1GGzzaoZiw== + dependencies: + "@smithy/util-buffer-from" "^4.2.0" + tslib "^2.6.2" + +"@smithy/util-waiter@^4.2.5": + version "4.2.5" + resolved "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-4.2.5.tgz" + integrity sha512-Dbun99A3InifQdIrsXZ+QLcC0PGBPAdrl4cj1mTgJvyc9N2zf7QSxg8TBkzsCmGJdE3TLbO9ycwpY0EkWahQ/g== + dependencies: + "@smithy/abort-controller" "^4.2.5" + "@smithy/types" "^4.9.0" + tslib "^2.6.2" + +"@smithy/uuid@^1.1.0": + version "1.1.0" + resolved "https://registry.npmjs.org/@smithy/uuid/-/uuid-1.1.0.tgz" + integrity sha512-4aUIteuyxtBUhVdiQqcDhKFitwfd9hqoSDYY2KRXiWtgoWJ9Bmise+KfEPDiVHWeJepvF8xJO9/9+WDIciMFFw== + dependencies: + tslib "^2.6.2" + +"@swc/helpers@0.5.15": + version "0.5.15" + resolved "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz" + integrity sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g== + dependencies: + tslib "^2.8.0" + +"@tailwindcss/node@4.1.17": + version "4.1.17" + resolved "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.17.tgz" + integrity sha512-csIkHIgLb3JisEFQ0vxr2Y57GUNYh447C8xzwj89U/8fdW8LhProdxvnVH6U8M2Y73QKiTIH+LWbK3V2BBZsAg== + dependencies: + "@jridgewell/remapping" "^2.3.4" + enhanced-resolve "^5.18.3" + jiti "^2.6.1" + lightningcss "1.30.2" + magic-string "^0.30.21" + source-map-js "^1.2.1" + tailwindcss "4.1.17" + +"@tailwindcss/oxide-android-arm64@4.1.17": + version "4.1.17" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.17.tgz#17f0dc901f88a979c5bff618181bce596dff596d" + integrity sha512-BMqpkJHgOZ5z78qqiGE6ZIRExyaHyuxjgrJ6eBO5+hfrfGkuya0lYfw8fRHG77gdTjWkNWEEm+qeG2cDMxArLQ== + +"@tailwindcss/oxide-darwin-arm64@4.1.17": + version "4.1.17" + resolved "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.17.tgz" + integrity sha512-EquyumkQweUBNk1zGEU/wfZo2qkp/nQKRZM8bUYO0J+Lums5+wl2CcG1f9BgAjn/u9pJzdYddHWBiFXJTcxmOg== + +"@tailwindcss/oxide-darwin-x64@4.1.17": + version "4.1.17" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.17.tgz#6dad270d2777508f55e2b73eca0eaef625bc45a7" + integrity sha512-gdhEPLzke2Pog8s12oADwYu0IAw04Y2tlmgVzIN0+046ytcgx8uZmCzEg4VcQh+AHKiS7xaL8kGo/QTiNEGRog== + +"@tailwindcss/oxide-freebsd-x64@4.1.17": + version "4.1.17" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.17.tgz#e7628b4602ac7d73c11a9922ecb83c24337eff55" + integrity sha512-hxGS81KskMxML9DXsaXT1H0DyA+ZBIbyG/sSAjWNe2EDl7TkPOBI42GBV3u38itzGUOmFfCzk1iAjDXds8Oh0g== + +"@tailwindcss/oxide-linux-arm-gnueabihf@4.1.17": + version "4.1.17" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.17.tgz#4d96a6fe4c7ed20e7a013101ee46f46caca2233e" + integrity sha512-k7jWk5E3ldAdw0cNglhjSgv501u7yrMf8oeZ0cElhxU6Y2o7f8yqelOp3fhf7evjIS6ujTI3U8pKUXV2I4iXHQ== + +"@tailwindcss/oxide-linux-arm64-gnu@4.1.17": + version "4.1.17" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.17.tgz#adc3c01cd73610870bfc21db5713571e08fb2210" + integrity sha512-HVDOm/mxK6+TbARwdW17WrgDYEGzmoYayrCgmLEw7FxTPLcp/glBisuyWkFz/jb7ZfiAXAXUACfyItn+nTgsdQ== + +"@tailwindcss/oxide-linux-arm64-musl@4.1.17": + version "4.1.17" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.17.tgz#39ceda30407af56a1ee125b2c5ce856c6d29250f" + integrity sha512-HvZLfGr42i5anKtIeQzxdkw/wPqIbpeZqe7vd3V9vI3RQxe3xU1fLjss0TjyhxWcBaipk7NYwSrwTwK1hJARMg== + +"@tailwindcss/oxide-linux-x64-gnu@4.1.17": + version "4.1.17" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.17.tgz#a3d4bd876c04d09856af0c394f5095fbc8a2b14c" + integrity sha512-M3XZuORCGB7VPOEDH+nzpJ21XPvK5PyjlkSFkFziNHGLc5d6g3di2McAAblmaSUNl8IOmzYwLx9NsE7bplNkwQ== + +"@tailwindcss/oxide-linux-x64-musl@4.1.17": + version "4.1.17" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.17.tgz#bdc20aa4fb2d28cc928f2cfffff7a9cd03a51d5b" + integrity sha512-k7f+pf9eXLEey4pBlw+8dgfJHY4PZ5qOUFDyNf7SI6lHjQ9Zt7+NcscjpwdCEbYi6FI5c2KDTDWyf2iHcCSyyQ== + +"@tailwindcss/oxide-wasm32-wasi@4.1.17": + version "4.1.17" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.17.tgz#7c0804748935928751838f86ff4f879c38f8a6d7" + integrity sha512-cEytGqSSoy7zK4JRWiTCx43FsKP/zGr0CsuMawhH67ONlH+T79VteQeJQRO/X7L0juEUA8ZyuYikcRBf0vsxhg== + dependencies: + "@emnapi/core" "^1.6.0" + "@emnapi/runtime" "^1.6.0" + "@emnapi/wasi-threads" "^1.1.0" + "@napi-rs/wasm-runtime" "^1.0.7" + "@tybys/wasm-util" "^0.10.1" + tslib "^2.4.0" + +"@tailwindcss/oxide-win32-arm64-msvc@4.1.17": + version "4.1.17" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.17.tgz#7222fc2ceee9d45ebe5aebf38707ee9833a20475" + integrity sha512-JU5AHr7gKbZlOGvMdb4722/0aYbU+tN6lv1kONx0JK2cGsh7g148zVWLM0IKR3NeKLv+L90chBVYcJ8uJWbC9A== + +"@tailwindcss/oxide-win32-x64-msvc@4.1.17": + version "4.1.17" + resolved "https://registry.yarnpkg.com/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.17.tgz#ac79087f451dfcd5c3099589027a5732b045a3bf" + integrity sha512-SKWM4waLuqx0IH+FMDUw6R66Hu4OuTALFgnleKbqhgGU30DY20NORZMZUKgLRjQXNN2TLzKvh48QXTig4h4bGw== + +"@tailwindcss/oxide@4.1.17": + version "4.1.17" + resolved "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.17.tgz" + integrity sha512-F0F7d01fmkQhsTjXezGBLdrl1KresJTcI3DB8EkScCldyKp3Msz4hub4uyYaVnk88BAS1g5DQjjF6F5qczheLA== + optionalDependencies: + "@tailwindcss/oxide-android-arm64" "4.1.17" + "@tailwindcss/oxide-darwin-arm64" "4.1.17" + "@tailwindcss/oxide-darwin-x64" "4.1.17" + "@tailwindcss/oxide-freebsd-x64" "4.1.17" + "@tailwindcss/oxide-linux-arm-gnueabihf" "4.1.17" + "@tailwindcss/oxide-linux-arm64-gnu" "4.1.17" + "@tailwindcss/oxide-linux-arm64-musl" "4.1.17" + "@tailwindcss/oxide-linux-x64-gnu" "4.1.17" + "@tailwindcss/oxide-linux-x64-musl" "4.1.17" + "@tailwindcss/oxide-wasm32-wasi" "4.1.17" + "@tailwindcss/oxide-win32-arm64-msvc" "4.1.17" + "@tailwindcss/oxide-win32-x64-msvc" "4.1.17" + +"@tailwindcss/postcss@4.1.17": + version "4.1.17" + resolved "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.1.17.tgz" + integrity sha512-+nKl9N9mN5uJ+M7dBOOCzINw94MPstNR/GtIhz1fpZysxL/4a+No64jCBD6CPN+bIHWFx3KWuu8XJRrj/572Dw== + dependencies: + "@alloc/quick-lru" "^5.2.0" + "@tailwindcss/node" "4.1.17" + "@tailwindcss/oxide" "4.1.17" + postcss "^8.4.41" + tailwindcss "4.1.17" + +"@tybys/wasm-util@^0.10.1": + version "0.10.1" + resolved "https://registry.yarnpkg.com/@tybys/wasm-util/-/wasm-util-0.10.1.tgz#ecddd3205cf1e2d5274649ff0eedd2991ed7f414" + integrity sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg== + dependencies: + tslib "^2.4.0" + +"@types/node@20.19.25": + version "20.19.25" + resolved "https://registry.npmjs.org/@types/node/-/node-20.19.25.tgz" + integrity sha512-ZsJzA5thDQMSQO788d7IocwwQbI8B5OPzmqNvpf3NY/+MHDAS759Wo0gd2WQeXYt5AAAQjzcrTVC6SKCuYgoCQ== + dependencies: + undici-types "~6.21.0" + +"@types/react-dom@19.2.3": + version "19.2.3" + resolved "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz" + integrity sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ== + +"@types/react@19.2.7": + version "19.2.7" + resolved "https://registry.npmjs.org/@types/react/-/react-19.2.7.tgz" + integrity sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg== + dependencies: + csstype "^3.2.2" + +abitype@1.1.0, abitype@^1.0.9: + version "1.1.0" + resolved "https://registry.npmjs.org/abitype/-/abitype-1.1.0.tgz" + integrity sha512-6Vh4HcRxNMLA0puzPjM5GBgT4aAcFGKZzSgAXvuZ27shJP6NEpielTuqbBmZILR5/xd0PizkBGy5hReKz9jl5A== + +bowser@^2.11.0: + version "2.13.1" + resolved "https://registry.npmjs.org/bowser/-/bowser-2.13.1.tgz" + integrity sha512-OHawaAbjwx6rqICCKgSG0SAnT05bzd7ppyKLVUITZpANBaaMFBAsaNkto3LoQ31tyFP5kNujE8Cdx85G9VzOkw== + +caniuse-lite@^1.0.30001579: + version "1.0.30001759" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001759.tgz#d569e7b010372c6b0ca3946e30dada0a2e9d5006" + integrity sha512-Pzfx9fOKoKvevQf8oCXoyNRQ5QyxJj+3O0Rqx2V5oxT61KGx8+n6hV/IUyJeifUci2clnmmKVpvtiqRzgiWjSw== + +client-only@0.0.1: + version "0.0.1" + resolved "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz" + integrity sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA== + +csstype@^3.2.2: + version "3.2.3" + resolved "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz" + integrity sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ== + +detect-libc@^2.0.3, detect-libc@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.1.2.tgz#689c5dcdc1900ef5583a4cb9f6d7b473742074ad" + integrity sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ== + +enhanced-resolve@^5.18.3: + version "5.18.3" + resolved "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz" + integrity sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww== + dependencies: + graceful-fs "^4.2.4" + tapable "^2.2.0" + +eventemitter3@5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz" + integrity sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA== + +fast-xml-parser@5.2.5: + version "5.2.5" + resolved "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.2.5.tgz" + integrity sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ== + dependencies: + strnum "^2.1.0" + +graceful-fs@^4.2.4: + version "4.2.11" + resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + +isows@1.0.7: + version "1.0.7" + resolved "https://registry.npmjs.org/isows/-/isows-1.0.7.tgz" + integrity sha512-I1fSfDCZL5P0v33sVqeTDSpcstAg/N+wF5HS033mogOVIp4B+oHC7oOCsA3axAbBSGTJ8QubbNmnIRN/h8U7hg== + +jiti@^2.6.1: + version "2.6.1" + resolved "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz" + integrity sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ== + +lightningcss-android-arm64@1.30.2: + version "1.30.2" + resolved "https://registry.yarnpkg.com/lightningcss-android-arm64/-/lightningcss-android-arm64-1.30.2.tgz#6966b7024d39c94994008b548b71ab360eb3a307" + integrity sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A== + +lightningcss-darwin-arm64@1.30.2: + version "1.30.2" + resolved "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.2.tgz" + integrity sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA== + +lightningcss-darwin-x64@1.30.2: + version "1.30.2" + resolved "https://registry.yarnpkg.com/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.2.tgz#5ce87e9cd7c4f2dcc1b713f5e8ee185c88d9b7cd" + integrity sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ== + +lightningcss-freebsd-x64@1.30.2: + version "1.30.2" + resolved "https://registry.yarnpkg.com/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.2.tgz#6ae1d5e773c97961df5cff57b851807ef33692a5" + integrity sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA== + +lightningcss-linux-arm-gnueabihf@1.30.2: + version "1.30.2" + resolved "https://registry.yarnpkg.com/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.2.tgz#62c489610c0424151a6121fa99d77731536cdaeb" + integrity sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA== + +lightningcss-linux-arm64-gnu@1.30.2: + version "1.30.2" + resolved "https://registry.yarnpkg.com/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.2.tgz#2a3661b56fe95a0cafae90be026fe0590d089298" + integrity sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A== + +lightningcss-linux-arm64-musl@1.30.2: + version "1.30.2" + resolved "https://registry.yarnpkg.com/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.2.tgz#d7ddd6b26959245e026bc1ad9eb6aa983aa90e6b" + integrity sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA== + +lightningcss-linux-x64-gnu@1.30.2: + version "1.30.2" + resolved "https://registry.yarnpkg.com/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.2.tgz#5a89814c8e63213a5965c3d166dff83c36152b1a" + integrity sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w== + +lightningcss-linux-x64-musl@1.30.2: + version "1.30.2" + resolved "https://registry.yarnpkg.com/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.2.tgz#808c2e91ce0bf5d0af0e867c6152e5378c049728" + integrity sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA== + +lightningcss-win32-arm64-msvc@1.30.2: + version "1.30.2" + resolved "https://registry.yarnpkg.com/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.2.tgz#ab4a8a8a2e6a82a4531e8bbb6bf0ff161ee6625a" + integrity sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ== + +lightningcss-win32-x64-msvc@1.30.2: + version "1.30.2" + resolved "https://registry.yarnpkg.com/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.2.tgz#f01f382c8e0a27e1c018b0bee316d210eac43b6e" + integrity sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw== + +lightningcss@1.30.2: + version "1.30.2" + resolved "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.2.tgz" + integrity sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ== + dependencies: + detect-libc "^2.0.3" + optionalDependencies: + lightningcss-android-arm64 "1.30.2" + lightningcss-darwin-arm64 "1.30.2" + lightningcss-darwin-x64 "1.30.2" + lightningcss-freebsd-x64 "1.30.2" + lightningcss-linux-arm-gnueabihf "1.30.2" + lightningcss-linux-arm64-gnu "1.30.2" + lightningcss-linux-arm64-musl "1.30.2" + lightningcss-linux-x64-gnu "1.30.2" + lightningcss-linux-x64-musl "1.30.2" + lightningcss-win32-arm64-msvc "1.30.2" + lightningcss-win32-x64-msvc "1.30.2" + +magic-string@^0.30.21: + version "0.30.21" + resolved "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz" + integrity sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ== + dependencies: + "@jridgewell/sourcemap-codec" "^1.5.5" + +nanoid@^3.3.11, nanoid@^3.3.6: + version "3.3.11" + resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz" + integrity sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w== + +next@16.0.7: + version "16.0.7" + resolved "https://registry.npmjs.org/next/-/next-16.0.7.tgz" + integrity sha512-3mBRJyPxT4LOxAJI6IsXeFtKfiJUbjCLgvXO02fV8Wy/lIhPvP94Fe7dGhUgHXcQy4sSuYwQNcOLhIfOm0rL0A== + dependencies: + "@next/env" "16.0.7" + "@swc/helpers" "0.5.15" + caniuse-lite "^1.0.30001579" + postcss "8.4.31" + styled-jsx "5.1.6" + optionalDependencies: + "@next/swc-darwin-arm64" "16.0.7" + "@next/swc-darwin-x64" "16.0.7" + "@next/swc-linux-arm64-gnu" "16.0.7" + "@next/swc-linux-arm64-musl" "16.0.7" + "@next/swc-linux-x64-gnu" "16.0.7" + "@next/swc-linux-x64-musl" "16.0.7" + "@next/swc-win32-arm64-msvc" "16.0.7" + "@next/swc-win32-x64-msvc" "16.0.7" + sharp "^0.34.4" + +ox@0.9.6: + version "0.9.6" + resolved "https://registry.npmjs.org/ox/-/ox-0.9.6.tgz" + integrity sha512-8SuCbHPvv2eZLYXrNmC0EC12rdzXQLdhnOMlHDW2wiCPLxBrOOJwX5L5E61by+UjTPOryqQiRSnjIKCI+GykKg== + dependencies: + "@adraffy/ens-normalize" "^1.11.0" + "@noble/ciphers" "^1.3.0" + "@noble/curves" "1.9.1" + "@noble/hashes" "^1.8.0" + "@scure/bip32" "^1.7.0" + "@scure/bip39" "^1.6.0" + abitype "^1.0.9" + eventemitter3 "5.0.1" + +picocolors@^1.0.0, picocolors@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz" + integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== + +postcss@8.4.31: + version "8.4.31" + resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz" + integrity sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ== + dependencies: + nanoid "^3.3.6" + picocolors "^1.0.0" + source-map-js "^1.0.2" + +postcss@^8.4.41: + version "8.5.6" + resolved "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz" + integrity sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg== + dependencies: + nanoid "^3.3.11" + picocolors "^1.1.1" + source-map-js "^1.2.1" + +react-dom@19.2.1: + version "19.2.1" + resolved "https://registry.npmjs.org/react-dom/-/react-dom-19.2.1.tgz" + integrity sha512-ibrK8llX2a4eOskq1mXKu/TGZj9qzomO+sNfO98M6d9zIPOEhlBkMkBUBLd1vgS0gQsLDBzA+8jJBVXDnfHmJg== + dependencies: + scheduler "^0.27.0" + +react@19.2.1: + version "19.2.1" + resolved "https://registry.npmjs.org/react/-/react-19.2.1.tgz" + integrity sha512-DGrYcCWK7tvYMnWh79yrPHt+vdx9tY+1gPZa7nJQtO/p8bLTDaHp4dzwEhQB7pZ4Xe3ok4XKuEPrVuc+wlpkmw== + +scheduler@^0.27.0: + version "0.27.0" + resolved "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz" + integrity sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q== + +semver@^7.7.3: + version "7.7.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.3.tgz#4b5f4143d007633a8dc671cd0a6ef9147b8bb946" + integrity sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q== + +sharp@^0.34.4: + version "0.34.5" + resolved "https://registry.yarnpkg.com/sharp/-/sharp-0.34.5.tgz#b6f148e4b8c61f1797bde11a9d1cfebbae2c57b0" + integrity sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg== + dependencies: + "@img/colour" "^1.0.0" + detect-libc "^2.1.2" + semver "^7.7.3" + optionalDependencies: + "@img/sharp-darwin-arm64" "0.34.5" + "@img/sharp-darwin-x64" "0.34.5" + "@img/sharp-libvips-darwin-arm64" "1.2.4" + "@img/sharp-libvips-darwin-x64" "1.2.4" + "@img/sharp-libvips-linux-arm" "1.2.4" + "@img/sharp-libvips-linux-arm64" "1.2.4" + "@img/sharp-libvips-linux-ppc64" "1.2.4" + "@img/sharp-libvips-linux-riscv64" "1.2.4" + "@img/sharp-libvips-linux-s390x" "1.2.4" + "@img/sharp-libvips-linux-x64" "1.2.4" + "@img/sharp-libvips-linuxmusl-arm64" "1.2.4" + "@img/sharp-libvips-linuxmusl-x64" "1.2.4" + "@img/sharp-linux-arm" "0.34.5" + "@img/sharp-linux-arm64" "0.34.5" + "@img/sharp-linux-ppc64" "0.34.5" + "@img/sharp-linux-riscv64" "0.34.5" + "@img/sharp-linux-s390x" "0.34.5" + "@img/sharp-linux-x64" "0.34.5" + "@img/sharp-linuxmusl-arm64" "0.34.5" + "@img/sharp-linuxmusl-x64" "0.34.5" + "@img/sharp-wasm32" "0.34.5" + "@img/sharp-win32-arm64" "0.34.5" + "@img/sharp-win32-ia32" "0.34.5" + "@img/sharp-win32-x64" "0.34.5" + +source-map-js@^1.0.2, source-map-js@^1.2.1: + version "1.2.1" + resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz" + integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== + +strnum@^2.1.0: + version "2.1.1" + resolved "https://registry.npmjs.org/strnum/-/strnum-2.1.1.tgz" + integrity sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw== + +styled-jsx@5.1.6: + version "5.1.6" + resolved "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz" + integrity sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA== + dependencies: + client-only "0.0.1" + +tailwindcss@4.1.17: + version "4.1.17" + resolved "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.17.tgz" + integrity sha512-j9Ee2YjuQqYT9bbRTfTZht9W/ytp5H+jJpZKiYdP/bpnXARAuELt9ofP0lPnmHjbga7SNQIxdTAXCmtKVYjN+Q== + +tapable@^2.2.0: + version "2.3.0" + resolved "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz" + integrity sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg== + +tslib@^2.4.0, tslib@^2.6.2, tslib@^2.8.0: + version "2.8.1" + resolved "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz" + integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== + +typescript@5.9.3: + version "5.9.3" + resolved "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz" + integrity sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw== + +undici-types@~6.21.0: + version "6.21.0" + resolved "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz" + integrity sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ== + +viem@2.40.3: + version "2.40.3" + resolved "https://registry.npmjs.org/viem/-/viem-2.40.3.tgz" + integrity sha512-feYfEpbgjRkZYQpwcgxqkWzjxHI5LSDAjcGetHHwDRuX9BRQHUdV8ohrCosCYpdEhus/RknD3/bOd4qLYVPPuA== + dependencies: + "@noble/curves" "1.9.1" + "@noble/hashes" "1.8.0" + "@scure/bip32" "1.7.0" + "@scure/bip39" "1.6.0" + abitype "1.1.0" + isows "1.0.7" + ox "0.9.6" + ws "8.18.3" + +ws@8.18.3: + version "8.18.3" + resolved "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz" + integrity sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==