diff --git a/.env.example b/.env.example deleted file mode 100644 index ef83220..0000000 --- a/.env.example +++ /dev/null @@ -1,10 +0,0 @@ -RPC_URL= -WSS_URL= - -JITO_URL=https://amsterdam.mainnet.block-engine.jito.wtf/api/v1/transactions?bundleOnly=true - -# Private key path -KEYPAIR_PATH=keypair.json - -# priority fees in micro lamports (1 million micro lamports are 1 lamport or 0.000000001 sol). Each fee is for 1 compute unit (uses 120k compute units for a snipe) -PRIORITY_FEES=1000000 # 1 lamport diff --git a/.github/workflows/pr-checks.yml b/.github/workflows/pr-checks.yml new file mode 100644 index 0000000..90d2c62 --- /dev/null +++ b/.github/workflows/pr-checks.yml @@ -0,0 +1,71 @@ +name: PR Checks + +on: + pull_request: + branches: [main] + +concurrency: + group: pr-checks-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + test: + runs-on: ubuntu-latest + env: + CARGO_NET_OFFLINE: "false" + steps: + - uses: actions/checkout@v4 + + - uses: dtolnay/rust-toolchain@stable + with: + components: clippy, rustfmt + + - uses: Swatinem/rust-cache@v2 + + - name: Install system dependencies + run: sudo apt-get update && sudo apt-get install -y pkg-config libssl-dev + + - name: Install cargo-make + uses: davidB/rust-cargo-make@v1 + + - name: Install cargo-nextest + uses: taiki-e/install-action@v2 + with: + tool: cargo-nextest + + - name: Install cargo-audit + uses: taiki-e/install-action@v2 + with: + tool: cargo-audit + + - name: Install cargo-deny + uses: taiki-e/install-action@v2 + with: + tool: cargo-deny + + - name: Audit Dependencies + run: cargo make audit + + - name: Deny Check + run: cargo make deny + + - name: Run Tests + run: cargo make test + + - name: Lint + run: cargo make clippy + + - name: Format Check + run: cargo make format-check + + - name: Architecture Guardrails (if configured) + shell: bash + run: | + if [[ -f scripts/check_architecture.sh ]]; then + cargo make architecture-check + else + echo "Skipping architecture-check: scripts/check_architecture.sh not found." + fi + + - name: Verify Publish Readiness + run: cargo publish --dry-run --locked diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..f57e8ce --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,348 @@ +name: Release + +on: + push: + tags: + - 'v*' + workflow_dispatch: + inputs: + tag: + description: 'Release tag to build/publish (for example: v0.1.0)' + required: true + type: string + +concurrency: + group: release-${{ github.ref_name || github.event.inputs.tag || github.run_id }} + cancel-in-progress: false + +permissions: + contents: read + +jobs: + resolve-tag: + name: Resolve Tag + runs-on: ubuntu-latest + outputs: + release_tag: ${{ steps.resolve.outputs.release_tag }} + clean_version: ${{ steps.resolve.outputs.clean_version }} + base_version: ${{ steps.resolve.outputs.base_version }} + is_prerelease: ${{ steps.resolve.outputs.is_prerelease }} + steps: + - id: resolve + shell: bash + run: | + if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then + TAG="${{ inputs.tag }}" + else + TAG="${GITHUB_REF_NAME}" + fi + + if [[ -z "${TAG}" || "${TAG}" != v* ]]; then + echo "Release tag must start with 'v'. Got: '${TAG}'" + exit 1 + fi + + CLEAN_VERSION="${TAG#v}" + BASE_VERSION="${CLEAN_VERSION%%-*}" + if [[ "${CLEAN_VERSION}" == *"-"* ]]; then + IS_PRERELEASE="true" + else + IS_PRERELEASE="false" + fi + + echo "release_tag=${TAG}" >> "${GITHUB_OUTPUT}" + echo "clean_version=${CLEAN_VERSION}" >> "${GITHUB_OUTPUT}" + echo "base_version=${BASE_VERSION}" >> "${GITHUB_OUTPUT}" + echo "is_prerelease=${IS_PRERELEASE}" >> "${GITHUB_OUTPUT}" + + validate: + name: Validate Release + needs: resolve-tag + runs-on: ubuntu-latest + env: + CARGO_NET_OFFLINE: "false" + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ needs.resolve-tag.outputs.release_tag }} + + - uses: dtolnay/rust-toolchain@stable + with: + components: clippy, rustfmt + + - uses: Swatinem/rust-cache@v2 + + - name: Install system dependencies + run: sudo apt-get update && sudo apt-get install -y pkg-config libssl-dev + + - name: Install cargo-make + uses: davidB/rust-cargo-make@v1 + + - name: Install cargo-nextest + uses: taiki-e/install-action@v2 + with: + tool: cargo-nextest + + - name: Install cargo-audit + uses: taiki-e/install-action@v2 + with: + tool: cargo-audit + + - name: Install cargo-deny + uses: taiki-e/install-action@v2 + with: + tool: cargo-deny + + - name: Verify Tag Matches Cargo.toml Version + shell: bash + run: | + VERSION_CLEAN="${{ needs.resolve-tag.outputs.clean_version }}" + VERSION_BASE="${{ needs.resolve-tag.outputs.base_version }}" + IS_PRERELEASE="${{ needs.resolve-tag.outputs.is_prerelease }}" + + TOML_VERSION="$(sed -n 's/^version = "\(.*\)"/\1/p' Cargo.toml | head -n 1)" + if [[ -z "${TOML_VERSION}" ]]; then + echo "Failed to read Cargo.toml version." + exit 1 + fi + + EXPECT_VERSION="${VERSION_CLEAN}" + if [[ "${IS_PRERELEASE}" == "true" ]]; then + EXPECT_VERSION="${VERSION_BASE}" + fi + + if [[ "${TOML_VERSION}" != "${EXPECT_VERSION}" ]]; then + echo "Tag version (${VERSION_CLEAN}) does not match Cargo.toml (${TOML_VERSION})." + exit 1 + fi + + - name: Verify Changelog Section (if CHANGELOG.md exists) + shell: bash + run: | + BASE_VERSION="${{ needs.resolve-tag.outputs.base_version }}" + if [[ -f CHANGELOG.md ]]; then + if ! grep -qE "^##[[:space:]]+${BASE_VERSION}$" CHANGELOG.md; then + echo "Missing CHANGELOG.md section for ${BASE_VERSION}." + exit 1 + fi + else + echo "CHANGELOG.md not found. Skipping changelog section validation." + fi + + - name: Release Tag Info + shell: bash + run: | + TAG="${{ needs.resolve-tag.outputs.release_tag }}" + IS_PRERELEASE="${{ needs.resolve-tag.outputs.is_prerelease }}" + BASE_VERSION="${{ needs.resolve-tag.outputs.base_version }}" + + if [[ "${IS_PRERELEASE}" == "true" ]]; then + { + echo "Detected pre-release tag: ${TAG}" + echo "Using base version for changelog/Cargo.toml checks: ${BASE_VERSION}" + echo "Crates.io publish is skipped for prerelease tags." + } >> "${GITHUB_STEP_SUMMARY}" + else + { + echo "Detected release tag: ${TAG}" + echo "Crates.io publish is enabled when CARGO_REGISTRY_TOKEN is available." + } >> "${GITHUB_STEP_SUMMARY}" + fi + + - name: Audit Dependencies + run: cargo make audit + + - name: Deny Check + run: cargo make deny + + - name: Run Tests + run: cargo make test + + - name: Lint + run: cargo make clippy + + - name: Format Check + run: cargo make format-check + + - name: Architecture Guardrails (if configured) + shell: bash + run: | + if [[ -f scripts/check_architecture.sh ]]; then + cargo make architecture-check + else + echo "Skipping architecture-check: scripts/check_architecture.sh not found." + fi + + - name: Verify Publish Readiness + run: cargo publish --dry-run --locked + + - name: Package Check + run: cargo package --locked + + publish-crates: + name: Publish to Crates.io + needs: [resolve-tag, validate] + if: needs.resolve-tag.outputs.is_prerelease == 'false' + runs-on: ubuntu-latest + env: + CARGO_NET_OFFLINE: "false" + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ needs.resolve-tag.outputs.release_tag }} + + - uses: dtolnay/rust-toolchain@stable + + - uses: Swatinem/rust-cache@v2 + + - name: Check CARGO_REGISTRY_TOKEN + id: token + shell: bash + env: + CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} + run: | + if [[ -z "${CARGO_REGISTRY_TOKEN}" ]]; then + echo "present=false" >> "${GITHUB_OUTPUT}" + echo "CARGO_REGISTRY_TOKEN is not configured. Skipping crates.io publish." >> "${GITHUB_STEP_SUMMARY}" + else + echo "present=true" >> "${GITHUB_OUTPUT}" + fi + + - name: Publish to Cargo + if: steps.token.outputs.present == 'true' + env: + CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} + run: cargo publish --locked + + build-binaries: + name: Build Binaries + needs: [resolve-tag, validate] + strategy: + matrix: + include: + - os: ubuntu-latest + target: x86_64-unknown-linux-gnu + suffix: linux-x86_64 + archive: tar.gz + - os: windows-latest + target: x86_64-pc-windows-msvc + suffix: windows-x86_64 + archive: zip + - os: macos-13 + target: x86_64-apple-darwin + suffix: macos-x86_64 + archive: tar.gz + - os: macos-14 + target: aarch64-apple-darwin + suffix: macos-arm64 + archive: tar.gz + runs-on: ${{ matrix.os }} + env: + CARGO_NET_OFFLINE: "false" + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ needs.resolve-tag.outputs.release_tag }} + + - uses: dtolnay/rust-toolchain@stable + with: + targets: ${{ matrix.target }} + + - uses: Swatinem/rust-cache@v2 + + - name: Install system dependencies (Linux) + if: startsWith(matrix.os, 'ubuntu') + run: sudo apt-get update && sudo apt-get install -y pkg-config libssl-dev + + - name: Build Release + run: cargo build --release --target ${{ matrix.target }} --locked + + - name: Package Assets + shell: bash + run: | + TAG="${{ needs.resolve-tag.outputs.release_tag }}" + BIN_NAME="sniper" + if [[ "${{ matrix.os }}" == "windows-latest" ]]; then + BIN_NAME="sniper.exe" + fi + + mkdir -p dist + cp "target/${{ matrix.target }}/release/${BIN_NAME}" dist/ + cp README.md LICENSE sniper.example.toml dist/ 2>/dev/null || : + + cd dist + if [[ "${{ matrix.archive }}" == "tar.gz" ]]; then + tar -czf "../sniper-${TAG}-${{ matrix.suffix }}.tar.gz" * + else + 7z a "../sniper-${TAG}-${{ matrix.suffix }}.zip" * + fi + + - name: Upload Build Artifact + uses: actions/upload-artifact@v4 + with: + name: sniper-${{ matrix.suffix }} + path: sniper-${{ needs.resolve-tag.outputs.release_tag }}-${{ matrix.suffix }}.${{ matrix.archive }} + if-no-files-found: error + + release: + name: Create GitHub Release + needs: [resolve-tag, build-binaries, publish-crates] + if: > + always() && + needs.build-binaries.result == 'success' && + (needs.publish-crates.result == 'success' || needs.publish-crates.result == 'skipped') + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ needs.resolve-tag.outputs.release_tag }} + + - name: Download Build Artifacts + uses: actions/download-artifact@v4 + with: + path: release-artifacts + merge-multiple: true + + - name: Build Release Notes + id: notes + shell: bash + run: | + TAG="${{ needs.resolve-tag.outputs.release_tag }}" + BASE_VERSION="${{ needs.resolve-tag.outputs.base_version }}" + NOTES_FILE="${RUNNER_TEMP}/release-notes.md" + + { + echo "### What's New" + echo + if [[ -f CHANGELOG.md ]] && grep -qE "^##[[:space:]]+${BASE_VERSION}$" CHANGELOG.md; then + awk -v version="${BASE_VERSION}" ' + $0 ~ "^##[[:space:]]+" version "$" { in_section=1; next } + in_section && $0 ~ "^##[[:space:]]+" { exit } + in_section { print } + ' CHANGELOG.md + else + echo "- Automated release for ${TAG}." + echo "- See commit history for details." + fi + echo + echo "### Installation" + echo '```bash' + echo 'cargo install sniper' + echo '```' + } > "${NOTES_FILE}" + + echo "path=${NOTES_FILE}" >> "${GITHUB_OUTPUT}" + + - name: Create or Update GitHub Release + uses: ncipollo/release-action@v1 + with: + tag: ${{ needs.resolve-tag.outputs.release_tag }} + name: Release ${{ needs.resolve-tag.outputs.release_tag }} + bodyFile: ${{ steps.notes.outputs.path }} + artifacts: release-artifacts/* + allowUpdates: true + omitBodyDuringUpdate: false + prerelease: ${{ needs.resolve-tag.outputs.is_prerelease == 'true' }} + makeLatest: ${{ needs.resolve-tag.outputs.is_prerelease == 'false' }} diff --git a/.gitignore b/.gitignore index 528529c..6725678 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ keypair.json -.env -target \ No newline at end of file +keypair.devnet.json +sniper.toml +target +log/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..3075af0 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,99 @@ +# Contributing + +## Scope + +This repository contains a latency-sensitive Solana sniper runtime. +Changes should prioritize: + +- correctness +- deterministic behavior +- stability under load +- measurable performance + +## Development Setup + +1. Install Rust stable: +```bash +rustup toolchain install stable +``` +2. Install cargo-make: +```bash +cargo install cargo-make +``` +3. Clone and enter the repo: +```bash +git clone +cd DeGeneRate +``` +4. Create local runtime config: +```bash +cp sniper.example.toml sniper.toml +``` + +Optional (for fuzzing): + +```bash +CARGO_NET_OFFLINE=false cargo install cargo-fuzz +rustup toolchain install nightly +``` + +## Local Quality Gates + +Run these before opening a PR: + +```bash +cargo make format-check +cargo make test +cargo make clippy +cargo make deny +cargo make audit +``` + +Optional: + +- `cargo make fuzz-all` (fuzz targets) +- `cargo make architecture-check` (only if `scripts/check_architecture.sh` exists) + +## Coding Rules + +- Keep domain rules explicit and type-safe (prefer newtypes for constrained values). +- Avoid floating-point math for money/percent math in execution paths. +- Prefer fixed-point / integer-safe transformations. +- Minimize allocations and lock contention on hot paths. +- Keep adapters isolated from domain logic. + +## Testing Guidance + +- Add unit tests for new pure logic. +- Add integration/e2e tests for behavior across boundaries. +- For parser/ingress logic, add or update fuzz targets when input surface expands. +- If changing latency-critical code, include benchmark/replay evidence where possible. + +## Pull Request Process + +1. Create a branch for your work. +2. Keep changes focused and atomic. +3. Update docs/config examples when behavior changes. +4. Ensure local quality gates pass. +5. Open a PR to `main` with: + - summary of changes + - risk notes / regressions considered + - validation performed (tests, fuzz, replay, etc.) + +## CI Expectations + +PRs run automated checks (`PR Checks` workflow), including tests, lint, formatting, and dependency/security checks. + +Release workflow runs on `v*` tags and can also be triggered manually. + +## Release Notes and Versioning + +- Use tags in the format `vX.Y.Z` (or prerelease like `vX.Y.Z-rc1`). +- Tag version must match `Cargo.toml` package version (prerelease tags compare on base version). +- If `CHANGELOG.md` exists, include a matching section for the release version. + +## Security and Secrets + +- Never commit private keys, RPC secrets, or tokens. +- Keep local keypairs and sensitive config out of version control. +- Use repository secrets for CI publishing (`CARGO_REGISTRY_TOKEN`). diff --git a/Cargo.lock b/Cargo.lock index 068846d..aadb369 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "Inflector" @@ -13,19 +13,10 @@ dependencies = [ ] [[package]] -name = "addr2line" -version = "0.22.0" +name = "adler2" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "aead" @@ -63,14 +54,39 @@ dependencies = [ "zeroize", ] +[[package]] +name = "agave-feature-set" +version = "3.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2846bb4fc0831d112255193a54259fabdc82149f0cd0a72db8922837cc62c0cd" +dependencies = [ + "ahash", + "solana-epoch-schedule", + "solana-hash 3.1.0", + "solana-pubkey 3.0.0", + "solana-sha256-hasher", + "solana-svm-feature-set", +] + +[[package]] +name = "agave-reserved-account-keys" +version = "3.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a55fff3d170fbcf81afc8d30c504a1ae4a6ff64be025ee6c08012f3db2a243fc" +dependencies = [ + "agave-feature-set", + "solana-pubkey 3.0.0", + "solana-sdk-ids", +] + [[package]] name = "ahash" -version = "0.8.11" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" dependencies = [ "cfg-if", - "getrandom 0.2.15", + "getrandom 0.3.4", "once_cell", "version_check", "zerocopy", @@ -78,9 +94,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] @@ -101,10 +117,10 @@ dependencies = [ ] [[package]] -name = "android-tzdata" -version = "0.1.1" +name = "allocator-api2" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "android_system_properties" @@ -126,165 +142,30 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.86" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" - -[[package]] -name = "aquamarine" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a941c39708478e8eea39243b5983f1c42d2717b3620ee91f4a52115fd02ac43f" -dependencies = [ - "itertools 0.9.0", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "aquamarine" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1da02abba9f9063d786eab1509833ebb2fac0f966862ca59439c76b9c566760" -dependencies = [ - "include_dir", - "itertools 0.10.5", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "ark-bn254" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a22f4561524cd949590d78d7d4c5df8f592430d221f7f3c9497bbafd8972120f" -dependencies = [ - "ark-ec", - "ark-ff", - "ark-std", -] - -[[package]] -name = "ark-ec" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" -dependencies = [ - "ark-ff", - "ark-poly", - "ark-serialize", - "ark-std", - "derivative", - "hashbrown 0.13.2", - "itertools 0.10.5", - "num-traits", - "zeroize", -] - -[[package]] -name = "ark-ff" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" -dependencies = [ - "ark-ff-asm", - "ark-ff-macros", - "ark-serialize", - "ark-std", - "derivative", - "digest 0.10.7", - "itertools 0.10.5", - "num-bigint 0.4.6", - "num-traits", - "paste", - "rustc_version", - "zeroize", -] - -[[package]] -name = "ark-ff-asm" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" -dependencies = [ - "quote", - "syn 1.0.109", -] - -[[package]] -name = "ark-ff-macros" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" -dependencies = [ - "num-bigint 0.4.6", - "num-traits", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "ark-poly" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" -dependencies = [ - "ark-ff", - "ark-serialize", - "ark-std", - "derivative", - "hashbrown 0.13.2", -] - -[[package]] -name = "ark-serialize" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" -dependencies = [ - "ark-serialize-derive", - "ark-std", - "digest 0.10.7", - "num-bigint 0.4.6", -] - -[[package]] -name = "ark-serialize-derive" -version = "0.4.2" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] +checksum = "5f0e0fee31ef5ed1ba1316088939cea399010ed7731dba877ed44aeb407a75ea" [[package]] -name = "ark-std" -version = "0.4.0" +name = "arc-swap" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +checksum = "f9f3647c145568cec02c42054e07bdf9a5a698e15b466fb2341bfc393cd24aa5" dependencies = [ - "num-traits", - "rand 0.8.5", + "rustversion", ] [[package]] name = "arrayref" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d151e35f61089500b617991b791fc8bfd237ae50cd5950803758a179b41e67a" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" [[package]] name = "arrayvec" -version = "0.7.4" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "ascii" @@ -304,7 +185,7 @@ dependencies = [ "nom", "num-traits", "rusticata-macros", - "thiserror", + "thiserror 1.0.69", "time", ] @@ -317,7 +198,7 @@ dependencies = [ "proc-macro2", "quote", "syn 1.0.109", - "synstructure", + "synstructure 0.12.6", ] [[package]] @@ -331,57 +212,46 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "assert_matches" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" - -[[package]] -name = "async-channel" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" -dependencies = [ - "concurrent-queue", - "event-listener", - "futures-core", -] - [[package]] name = "async-compression" -version = "0.4.12" +version = "0.4.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fec134f64e2bc57411226dfc4e52dec859ddfc7e711fc5e07b612584f000e4aa" +checksum = "68650b7df54f0293fd061972a0fb05aaf4fc0879d3b3d21a638a182c5c543b9f" dependencies = [ - "brotli", - "flate2", - "futures-core", - "memchr", + "compression-codecs", + "compression-core", "pin-project-lite", "tokio", ] [[package]] -name = "async-mutex" -version = "1.4.0" +name = "async-lock" +version = "3.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479db852db25d9dbf6204e6cb6253698f175c15726470f78af0d918e99d6156e" +checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311" dependencies = [ "event-listener", + "event-listener-strategy", + "pin-project-lite", ] [[package]] name = "async-trait" -version = "0.1.81" +version = "0.1.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.115", ] +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + [[package]] name = "atty" version = "0.2.14" @@ -395,30 +265,15 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" - -[[package]] -name = "backtrace" -version = "0.3.73" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" -dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] -name = "base64" -version = "0.12.3" +name = "base16ct" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" [[package]] name = "base64" @@ -428,15 +283,15 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.21.7" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] -name = "base64" -version = "0.22.1" +name = "base64ct" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" [[package]] name = "bincode" @@ -455,44 +310,38 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.6.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" dependencies = [ - "serde", + "serde_core", ] [[package]] -name = "bitmaps" -version = "2.1.0" +name = "bitvec" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "031043d04099746d8db04daf1fa424b2bc8bd69d92b25962dcde24da39ab64a2" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" dependencies = [ - "typenum", + "funty", + "radium", + "tap", + "wyz", ] [[package]] name = "blake3" -version = "1.5.1" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30cca6d3674597c30ddf2c587bf8d9d65c9a84d2326d941cc79c9842dfe0ef52" +checksum = "2468ef7d57b3fb7e16b576e8377cdbde2320c60e1491e961d11da40fc4f02a2d" dependencies = [ "arrayref", "arrayvec", "cc", "cfg-if", "constant_time_eq", - "digest 0.10.7", -] - -[[package]] -name = "block-buffer" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" -dependencies = [ - "block-padding", - "generic-array", + "cpufeatures", + "digest", ] [[package]] @@ -505,85 +354,61 @@ dependencies = [ ] [[package]] -name = "block-padding" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" - -[[package]] -name = "borsh" -version = "0.10.3" +name = "blst" +version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4114279215a005bc675e386011e594e1d9b800918cea18fcadadcce864a2046b" +checksum = "dcdb4c7013139a150f9fc55d123186dbfaba0d912817466282c73ac49e71fb45" dependencies = [ - "borsh-derive 0.10.3", - "hashbrown 0.13.2", + "cc", + "glob", + "threadpool", + "zeroize", ] [[package]] -name = "borsh" -version = "1.5.1" +name = "blstrs" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6362ed55def622cddc70a4746a68554d7b687713770de539e59a739b249f8ed" +checksum = "7a8a8ed6fefbeef4a8c7b460e4110e12c5e22a5b7cf32621aae6ad650c4dcf29" dependencies = [ - "borsh-derive 1.5.1", - "cfg_aliases 0.2.1", + "blst", + "byte-slice-cast", + "ff", + "group", + "pairing", + "rand_core 0.6.4", + "serde", + "subtle", ] [[package]] -name = "borsh-derive" -version = "0.10.3" +name = "borsh" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0754613691538d51f329cce9af41d7b7ca150bc973056f1156611489475f54f7" +checksum = "d1da5ab77c1437701eeff7c88d968729e7766172279eab0676857b3d63af7a6f" dependencies = [ - "borsh-derive-internal", - "borsh-schema-derive-internal", - "proc-macro-crate 0.1.5", - "proc-macro2", - "syn 1.0.109", + "borsh-derive", + "cfg_aliases", ] [[package]] name = "borsh-derive" -version = "1.5.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3ef8005764f53cd4dca619f5bf64cafd4664dada50ece25e4d81de54c80cc0b" +checksum = "0686c856aa6aac0c4498f936d7d6a02df690f614c03e4d906d1018062b5c5e2c" dependencies = [ "once_cell", - "proc-macro-crate 3.1.0", - "proc-macro2", - "quote", - "syn 2.0.72", - "syn_derive", -] - -[[package]] -name = "borsh-derive-internal" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afb438156919598d2c7bad7e1c0adf3d26ed3840dbc010db1a882a65583ca2fb" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "borsh-schema-derive-internal" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634205cc43f74a1b9046ef87c4540ebda95696ec0f315024860cad7c5b0f5ccd" -dependencies = [ + "proc-macro-crate", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.115", ] [[package]] name = "brotli" -version = "6.0.0" +version = "8.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74f7971dbd9326d58187408ab83117d8ac1bb9c17b085fdacd1cf2f598719b6b" +checksum = "4bd8b9603c7aa97359dbd97ecf258968c95f3adddd6db2f7e7a5bef101c84560" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -592,9 +417,9 @@ dependencies = [ [[package]] name = "brotli-decompressor" -version = "4.0.1" +version = "5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a45bd2e4095a8b518033b128020dd4a55aab1c0a381ba4404a472630f4bc362" +checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -611,9 +436,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.16.0" +version = "3.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" [[package]] name = "bv" @@ -625,24 +450,30 @@ dependencies = [ "serde", ] +[[package]] +name = "byte-slice-cast" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7575182f7272186991736b70173b0ea045398f984bf5ebbb3804736ce1330c9d" + [[package]] name = "bytemuck" -version = "1.16.3" +version = "1.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "102087e286b4677862ea56cf8fc58bb2cdfa8725c40ffb80fe3a008eb7f2fc83" +checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" dependencies = [ "bytemuck_derive", ] [[package]] name = "bytemuck_derive" -version = "1.7.0" +version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ee891b04274a59bd38b412188e24b849617b2e45a0fd8d057deb63e7403761b" +checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.115", ] [[package]] @@ -653,62 +484,45 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" - -[[package]] -name = "bzip2" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" -dependencies = [ - "bzip2-sys", - "libc", -] - -[[package]] -name = "bzip2-sys" -version = "0.1.11+1.0.8" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" dependencies = [ - "cc", - "libc", - "pkg-config", + "serde", ] [[package]] name = "caps" -version = "0.5.5" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "190baaad529bcfbde9e1a19022c42781bdb6ff9de25721abdb8fd98c0807730b" +checksum = "fd1ddba47aba30b6a889298ad0109c3b8dcb0e8fc993b459daa7067d46f865e0" dependencies = [ "libc", - "thiserror", ] [[package]] name = "cc" -version = "1.1.7" +version = "1.2.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26a5c3fd7bfa1ce3897a3a3501d362b2d87b7f2583ebcb4a949ec25911025cbc" +checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" dependencies = [ + "find-msvc-tools", "jobserver", "libc", + "shlex", ] [[package]] -name = "cfg-if" -version = "1.0.0" +name = "cesu8" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" [[package]] -name = "cfg_aliases" -version = "0.1.1" +name = "cfg-if" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "cfg_aliases" @@ -716,28 +530,29 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" +[[package]] +name = "cfg_eval" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45565fc9416b9896014f5732ac776f810ee53a66730c17e4020c3ec064a8f88f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", +] + [[package]] name = "chrono" -version = "0.4.38" +version = "0.4.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +checksum = "fac4744fb15ae8337dc853fee7fb3f4e48c0fbaa23d0afe49c447b4fab126118" dependencies = [ - "android-tzdata", "iana-time-zone", "js-sys", "num-traits", "serde", "wasm-bindgen", - "windows-targets 0.52.6", -] - -[[package]] -name = "chrono-humanize" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "799627e6b4d27827a814e837b9d8a504832086081806d45b1afa34dc982b023b" -dependencies = [ - "chrono", + "windows-link", ] [[package]] @@ -760,36 +575,11 @@ dependencies = [ "atty", "bitflags 1.3.2", "strsim 0.8.0", - "textwrap 0.11.0", - "unicode-width", + "textwrap", + "unicode-width 0.1.14", "vec_map", ] -[[package]] -name = "clap" -version = "3.2.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" -dependencies = [ - "atty", - "bitflags 1.3.2", - "clap_lex", - "indexmap 1.9.3", - "once_cell", - "strsim 0.10.0", - "termcolor", - "textwrap 0.16.1", -] - -[[package]] -name = "clap_lex" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" -dependencies = [ - "os_str_bytes", -] - [[package]] name = "colored" version = "1.9.4" @@ -803,12 +593,12 @@ dependencies = [ [[package]] name = "colored" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8" +checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c" dependencies = [ "lazy_static", - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] @@ -824,6 +614,34 @@ dependencies = [ "unreachable", ] +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "compression-codecs" +version = "0.4.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00828ba6fd27b45a448e57dbfe84f1029d4c9f26b368157e9a448a5f49a2ec2a" +dependencies = [ + "brotli", + "compression-core", + "flate2", + "memchr", +] + +[[package]] +name = "compression-core" +version = "0.4.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75984efb6ed102a0d42db99afb6c1948f0380d1d91808d5529916e6c08b49d8d" + [[package]] name = "concurrent-queue" version = "2.5.0" @@ -835,54 +653,47 @@ dependencies = [ [[package]] name = "console" -version = "0.15.8" +version = "0.15.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" +checksum = "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8" dependencies = [ "encode_unicode", - "lazy_static", "libc", - "unicode-width", - "windows-sys 0.52.0", + "once_cell", + "unicode-width 0.2.2", + "windows-sys 0.59.0", ] [[package]] -name = "console_error_panic_hook" -version = "0.1.7" +name = "console" +version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +checksum = "03e45a4a8926227e4197636ba97a9fc9b00477e9f4bd711395687c5f0734bec4" dependencies = [ - "cfg-if", - "wasm-bindgen", + "encode_unicode", + "libc", + "once_cell", + "unicode-width 0.2.2", + "windows-sys 0.61.2", ] [[package]] -name = "console_log" -version = "0.2.2" +name = "const-oid" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89f72f65e8501878b8a004d5a1afb780987e2ce2b4532c562e367a72c57499f" -dependencies = [ - "log", - "web-sys", -] +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "constant_time_eq" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" - -[[package]] -name = "convert_case" -version = "0.4.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" +checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b" [[package]] name = "core-foundation" -version = "0.9.4" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" dependencies = [ "core-foundation-sys", "libc", @@ -890,42 +701,42 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.12" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" dependencies = [ "libc", ] [[package]] name = "crc32fast" -version = "1.4.2" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" dependencies = [ "cfg-if", ] [[package]] name = "crossbeam-channel" -version = "0.5.13" +version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-deque" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -942,35 +753,31 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" - -[[package]] -name = "crunchy" -version = "0.2.2" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] -name = "crypto-common" -version = "0.1.6" +name = "crypto-bigint" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ "generic-array", "rand_core 0.6.4", - "typenum", + "subtle", + "zeroize", ] [[package]] -name = "crypto-mac" -version = "0.8.0" +name = "crypto-common" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" dependencies = [ "generic-array", - "subtle", + "rand_core 0.6.4", + "typenum", ] [[package]] @@ -984,86 +791,66 @@ dependencies = [ [[package]] name = "curve25519-dalek" -version = "3.2.1" +version = "4.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90f9d052967f590a76e62eb387bd0bbb1b000182c3cefe5364db6b7211651bc0" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" dependencies = [ - "byteorder", - "digest 0.9.0", - "rand_core 0.5.1", + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest", + "fiat-crypto", + "rand_core 0.6.4", + "rustc_version", "serde", "subtle", "zeroize", ] [[package]] -name = "darling" -version = "0.13.4" +name = "curve25519-dalek-derive" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ - "darling_core 0.13.4", - "darling_macro 0.13.4", + "proc-macro2", + "quote", + "syn 2.0.115", ] [[package]] name = "darling" -version = "0.20.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" -dependencies = [ - "darling_core 0.20.10", - "darling_macro 0.20.10", -] - -[[package]] -name = "darling_core" -version = "0.13.4" +version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" +checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim 0.10.0", - "syn 1.0.109", + "darling_core", + "darling_macro", ] [[package]] name = "darling_core" -version = "0.20.10" +version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.72", -] - -[[package]] -name = "darling_macro" -version = "0.13.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" -dependencies = [ - "darling_core 0.13.4", - "quote", - "syn 1.0.109", + "syn 2.0.115", ] [[package]] name = "darling_macro" -version = "0.20.10" +version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" dependencies = [ - "darling_core 0.20.10", + "darling_core", "quote", - "syn 2.0.72", + "syn 2.0.115", ] [[package]] @@ -1077,14 +864,23 @@ dependencies = [ "lock_api", "once_cell", "parking_lot_core", - "rayon", ] [[package]] name = "data-encoding" -version = "2.6.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" +checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea" + +[[package]] +name = "der" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +dependencies = [ + "const-oid", + "zeroize", +] [[package]] name = "der-parser" @@ -1102,9 +898,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.3.11" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +checksum = "cc3dc5ad92c2e2d1c193bbbbdf2ea477cb81331de4f3103f267ca18368b988c4" dependencies = [ "powerfmt", ] @@ -1115,77 +911,30 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e5c37193a1db1d8ed868c03ec7b152175f26160a5b740e5e484143877e0adf0" -[[package]] -name = "derivative" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "derive_more" -version = "0.99.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" -dependencies = [ - "convert_case", - "proc-macro2", - "quote", - "rustc_version", - "syn 2.0.72", -] - [[package]] name = "dialoguer" version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59c6f2989294b9a498d3ad5491a79c6deb604617378e1cdc4bfc1c1361fe2f87" dependencies = [ - "console", + "console 0.15.11", "shell-words", "tempfile", "zeroize", ] -[[package]] -name = "difflib" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" - -[[package]] -name = "digest" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" -dependencies = [ - "generic-array", -] - [[package]] name = "digest" version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer 0.10.4", + "block-buffer", + "const-oid", "crypto-common", "subtle", ] -[[package]] -name = "dir-diff" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7ad16bf5f84253b50d6557681c58c3ab67c47c77d39fed9aeb56e947290bd10" -dependencies = [ - "walkdir", -] - [[package]] name = "dirs-next" version = "2.0.0" @@ -1215,7 +964,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.115", ] [[package]] @@ -1238,103 +987,96 @@ checksum = "a6cbae11b3de8fce2a456e8ea3dada226b35fe791f0dc1d360c0941f0bb681f3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.115", ] [[package]] -name = "dotenv" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" - -[[package]] -name = "downcast" -version = "0.11.0" +name = "eager" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1" +checksum = "abe71d579d1812060163dff96056261deb5bf6729b100fa2e36a68b9649ba3d3" [[package]] -name = "dptree" -version = "0.3.0" +name = "ecdsa" +version = "0.16.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d81175dab5ec79c30e0576df2ed2c244e1721720c302000bb321b107e82e265c" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" dependencies = [ - "futures", + "der", + "digest", + "elliptic-curve", + "rfc6979", + "signature", + "spki", ] -[[package]] -name = "eager" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abe71d579d1812060163dff96056261deb5bf6729b100fa2e36a68b9649ba3d3" - [[package]] name = "ed25519" -version = "1.5.3" +version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" dependencies = [ + "pkcs8", "signature", ] [[package]] name = "ed25519-dalek" -version = "1.0.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" +checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9" dependencies = [ "curve25519-dalek", "ed25519", - "rand 0.7.3", + "rand_core 0.6.4", "serde", - "sha2 0.9.9", + "sha2", + "subtle", "zeroize", ] [[package]] name = "ed25519-dalek-bip32" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d2be62a4061b872c8c0873ee4fc6f101ce7b889d039f019c5fa2af471a59908" +checksum = "6b49a684b133c4980d7ee783936af771516011c8cd15f429dbda77245e282f03" dependencies = [ "derivation-path", "ed25519-dalek", - "hmac 0.12.1", - "sha2 0.10.8", -] - -[[package]] -name = "educe" -version = "0.4.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f0042ff8246a363dbe77d2ceedb073339e85a804b9a47636c6e016a9a32c05f" -dependencies = [ - "enum-ordinalize", - "proc-macro2", - "quote", - "syn 1.0.109", + "hmac", + "sha2", ] [[package]] name = "either" -version = "1.13.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] -name = "encode_unicode" -version = "0.3.6" +name = "elliptic-curve" +version = "0.13.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest", + "ff", + "generic-array", + "group", + "pkcs8", + "rand_core 0.6.4", + "sec1", + "subtle", + "zeroize", +] [[package]] -name = "encoding_rs" -version = "0.8.34" +name = "encode_unicode" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" -dependencies = [ - "cfg-if", -] +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" [[package]] name = "enum-iterator" @@ -1347,78 +1089,69 @@ dependencies = [ [[package]] name = "enum-iterator-derive" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1ab991c1362ac86c61ab6f556cff143daa22e5a15e4e189df818b2fd19fe65b" +checksum = "685adfa4d6f3d765a26bc5dbc936577de9abf756c1feeb3089b01dd395034842" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.115", ] [[package]] -name = "enum-ordinalize" -version = "3.1.15" +name = "equivalent" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bf1fa3f06bbff1ea5b1a9c7b14aa992a39657db60a2759457328d7e058f49ee" -dependencies = [ - "num-bigint 0.4.6", - "num-traits", - "proc-macro2", - "quote", - "syn 2.0.72", -] +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] -name = "env_logger" -version = "0.9.3" +name = "errno" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ - "atty", - "humantime", - "log", - "regex", - "termcolor", + "libc", + "windows-sys 0.61.2", ] [[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "erasable" -version = "1.2.1" +name = "event-listener" +version = "5.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f11890ce181d47a64e5d1eb4b6caba0e7bae911a356723740d058a5d0340b7d" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" dependencies = [ - "autocfg", - "scopeguard", + "concurrent-queue", + "parking", + "pin-project-lite", ] [[package]] -name = "errno" -version = "0.3.9" +name = "event-listener-strategy" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" dependencies = [ - "libc", - "windows-sys 0.52.0", + "event-listener", + "pin-project-lite", ] [[package]] -name = "event-listener" -version = "2.5.3" +name = "fastbloom" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" +checksum = "4e7f34442dbe69c60fe8eaf58a8cafff81a1f278816d8ab4db255b3bef4ac3c4" +dependencies = [ + "getrandom 0.3.4", + "libm", + "rand 0.9.2", + "siphasher 1.0.2", +] [[package]] name = "fastrand" -version = "2.1.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "feature-probe" @@ -1437,83 +1170,94 @@ dependencies = [ ] [[package]] -name = "filetime" -version = "0.2.23" +name = "ff" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" +checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" dependencies = [ - "cfg-if", - "libc", - "redox_syscall 0.4.1", - "windows-sys 0.52.0", + "bitvec", + "rand_core 0.6.4", + "subtle", ] [[package]] -name = "fixedbitset" -version = "0.4.2" +name = "fiat-crypto" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" [[package]] -name = "flate2" -version = "1.0.31" +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "five8" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f211bbe8e69bbd0cfdea405084f128ae8b4aaa6b0b522fc8f2b009084797920" +checksum = "23f76610e969fa1784327ded240f1e28a3fd9520c9cec93b636fcf62dd37f772" dependencies = [ - "crc32fast", - "miniz_oxide", + "five8_core", ] [[package]] -name = "float-cmp" -version = "0.9.0" +name = "five8_const" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" +checksum = "1a0f1728185f277989ca573a402716ae0beaaea3f76a8ff87ef9dd8fb19436c5" dependencies = [ - "num-traits", + "five8_core", ] [[package]] -name = "fnv" -version = "1.0.7" +name = "five8_core" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +checksum = "059c31d7d36c43fe39d89e55711858b4da8be7eb6dabac23c7289b1a19489406" [[package]] -name = "foreign-types" -version = "0.3.2" +name = "flate2" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" dependencies = [ - "foreign-types-shared", + "crc32fast", + "miniz_oxide", ] [[package]] -name = "foreign-types-shared" -version = "0.1.1" +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" [[package]] name = "form_urlencoded" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" dependencies = [ "percent-encoding", ] [[package]] -name = "fragile" +name = "funty" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", @@ -1526,9 +1270,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", "futures-sink", @@ -1536,15 +1280,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", @@ -1553,38 +1297,44 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-macro" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.115", ] [[package]] name = "futures-sink" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-timer" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-channel", "futures-core", @@ -1604,9 +1354,9 @@ version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ - "serde", "typenum", "version_check", + "zeroize", ] [[package]] @@ -1621,101 +1371,120 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.1.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ "cfg-if", "js-sys", "libc", - "wasi 0.9.0+wasi-snapshot-preview1", + "wasi", "wasm-bindgen", ] [[package]] name = "getrandom" -version = "0.2.15" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", "js-sys", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "r-efi", + "wasip2", "wasm-bindgen", ] [[package]] -name = "gimli" -version = "0.29.0" +name = "getrandom" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139ef39800118c7683f2fd3c98c1b23c09ae076556b435f8e9064ae108aaeeec" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", + "wasip3", +] + +[[package]] +name = "glob" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" [[package]] -name = "goblin" -version = "0.5.4" +name = "governor" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7666983ed0dd8d21a6f6576ee00053ca0926fb281a5522577a4dbd0f1b54143" +checksum = "68a7f542ee6b35af73b06abc0dad1c1bae89964e4e253bc4b587b91c9637867b" dependencies = [ - "log", - "plain", - "scroll", + "cfg-if", + "dashmap", + "futures", + "futures-timer", + "no-std-compat", + "nonzero_ext", + "parking_lot", + "portable-atomic", + "quanta", + "rand 0.8.5", + "smallvec", + "spinning_top", ] [[package]] -name = "h2" -version = "0.3.26" +name = "group" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http 0.2.12", - "indexmap 2.3.0", - "slab", - "tokio", - "tokio-util 0.7.11", - "tracing", + "ff", + "rand 0.8.5", + "rand_core 0.6.4", + "rand_xorshift", + "subtle", ] [[package]] name = "hash32" -version = "0.2.1" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" +checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" dependencies = [ "byteorder", ] [[package]] name = "hashbrown" -version = "0.12.3" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] name = "hashbrown" -version = "0.13.2" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" dependencies = [ - "ahash", + "allocator-api2", + "equivalent", + "foldhash", ] [[package]] name = "hashbrown" -version = "0.14.5" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" [[package]] name = "heck" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" @@ -1728,9 +1497,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.3.9" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" [[package]] name = "histogram" @@ -1738,43 +1507,13 @@ version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "12cb882ccb290b8646e554b157ab0b71e64e8d5bef775cd66b6531e52d302669" -[[package]] -name = "hmac" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" -dependencies = [ - "crypto-mac", - "digest 0.9.0", -] - [[package]] name = "hmac" version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" dependencies = [ - "digest 0.10.7", -] - -[[package]] -name = "hmac-drbg" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1" -dependencies = [ - "digest 0.9.0", - "generic-array", - "hmac 0.8.1", -] - -[[package]] -name = "home" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" -dependencies = [ - "windows-sys 0.52.0", + "digest", ] [[package]] @@ -1790,105 +1529,121 @@ dependencies = [ [[package]] name = "http" -version = "1.1.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" dependencies = [ "bytes", - "fnv", "itoa", ] [[package]] name = "http-body" -version = "0.4.6" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 0.2.12", - "pin-project-lite", + "http 1.4.0", ] [[package]] -name = "httparse" -version = "1.9.4" +name = "http-body-util" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http 1.4.0", + "http-body", + "pin-project-lite", +] [[package]] -name = "httpdate" -version = "1.0.3" +name = "httparse" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" [[package]] name = "humantime" -version = "2.1.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" +checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424" [[package]] name = "hyper" -version = "0.14.30" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a152ddd61dfaec7273fe8419ab357f33aee0d914c5f4efbf0d96fa749eea5ec9" +checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" dependencies = [ + "atomic-waker", "bytes", "futures-channel", "futures-core", - "futures-util", - "h2", - "http 0.2.12", + "http 1.4.0", "http-body", "httparse", - "httpdate", "itoa", "pin-project-lite", - "socket2", + "pin-utils", + "smallvec", "tokio", - "tower-service", - "tracing", "want", ] [[package]] name = "hyper-rustls" -version = "0.24.2" +version = "0.27.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" dependencies = [ - "futures-util", - "http 0.2.12", + "http 1.4.0", "hyper", + "hyper-util", "rustls", + "rustls-pki-types", "tokio", "tokio-rustls", + "tower-service", + "webpki-roots 1.0.6", ] [[package]] -name = "hyper-tls" -version = "0.5.0" +name = "hyper-util" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" dependencies = [ + "base64 0.22.1", "bytes", + "futures-channel", + "futures-util", + "http 1.4.0", + "http-body", "hyper", - "native-tls", + "ipnet", + "libc", + "percent-encoding", + "pin-project-lite", + "socket2", "tokio", - "tokio-native-tls", + "tower-service", + "tracing", ] [[package]] name = "iana-time-zone" -version = "0.1.60" +version = "0.1.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", + "log", "wasm-bindgen", "windows-core", ] @@ -1903,178 +1658,234 @@ dependencies = [ ] [[package]] -name = "ident_case" -version = "1.0.1" +name = "icu_collections" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] [[package]] -name = "idna" -version = "0.5.0" +name = "icu_locale_core" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", ] [[package]] -name = "im" -version = "15.1.0" +name = "icu_normalizer" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0acd33ff0285af998aaf9b57342af478078f53492322fafc47450e09397e0e9" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" dependencies = [ - "bitmaps", - "rand_core 0.6.4", - "rand_xoshiro", - "rayon", - "serde", - "sized-chunks", - "typenum", - "version_check", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", ] [[package]] -name = "include_dir" -version = "0.7.4" +name = "icu_normalizer_data" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" + +[[package]] +name = "icu_properties" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "923d117408f1e49d914f1a379a309cffe4f18c05cf4e3d12e613a15fc81bd0dd" +checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" dependencies = [ - "include_dir_macros", + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", ] [[package]] -name = "include_dir_macros" -version = "0.7.4" +name = "icu_properties_data" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cab85a7ed0bd5f0e76d93846e0147172bed2e2d3f859bcc33a8d9699cad1a75" +checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" + +[[package]] +name = "icu_provider" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" dependencies = [ - "proc-macro2", - "quote", + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", ] [[package]] -name = "index_list" -version = "0.2.13" +name = "id-arena" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e6ba961c14e98151cd6416dd3685efe786a94c38bc1a535c06ceff0a1600813" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" [[package]] -name = "indexmap" -version = "1.9.3" +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 = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" dependencies = [ - "autocfg", - "hashbrown 0.12.3", + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", ] [[package]] name = "indexmap" -version = "2.3.0" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3fc2e30ba82dd1b3911c8de1ffc143c74a914a14e99514d7637e3099df5ea0" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" dependencies = [ "equivalent", - "hashbrown 0.14.5", + "hashbrown 0.16.1", + "serde", + "serde_core", ] [[package]] name = "indicatif" -version = "0.17.8" +version = "0.18.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "763a5a8f45087d6bcea4222e7b72c291a054edf80e4ef6efd2a4979878c7bea3" +checksum = "9375e112e4b463ec1b1c6c011953545c65a30164fbab5b581df32b3abf0dcb88" dependencies = [ - "console", - "instant", - "number_prefix", + "console 0.16.2", "portable-atomic", - "unicode-width", + "unicode-width 0.2.2", + "unit-prefix", + "web-time", ] [[package]] name = "inout" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" dependencies = [ "generic-array", ] [[package]] -name = "instant" -version = "0.1.13" +name = "ipnet" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" -dependencies = [ - "cfg-if", -] +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" [[package]] -name = "ipnet" -version = "2.9.0" +name = "iri-string" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a" +dependencies = [ + "memchr", + "serde", +] [[package]] name = "is-terminal" -version = "0.4.12" +version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" +checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46" dependencies = [ - "hermit-abi 0.3.9", + "hermit-abi 0.5.2", "libc", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] name = "itertools" -version = "0.9.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" dependencies = [ "either", ] [[package]] -name = "itertools" -version = "0.10.5" +name = "itoa" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" [[package]] -name = "itertools" -version = "0.12.1" +name = "jni" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" dependencies = [ - "either", + "cesu8", + "cfg-if", + "combine 4.6.7", + "jni-sys", + "log", + "thiserror 1.0.69", + "walkdir", + "windows-sys 0.45.0", ] [[package]] -name = "itoa" -version = "1.0.11" +name = "jni-sys" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "jobserver" -version = "0.1.32" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" dependencies = [ + "getrandom 0.3.4", "libc", ] [[package]] name = "js-sys" -version = "0.3.69" +version = "0.3.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3" dependencies = [ + "once_cell", "wasm-bindgen", ] @@ -2093,11 +1904,25 @@ dependencies = [ "serde_json", ] +[[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", + "sha2", + "signature", +] + [[package]] name = "keccak" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +checksum = "cb26cec98cce3a3d96cbb7bced3c4b16e3d13f27ec56dbd62cbc8f39cfb9d653" dependencies = [ "cpufeatures", ] @@ -2109,150 +1934,84 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] -name = "libc" -version = "0.2.155" +name = "leb128fmt" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" [[package]] -name = "libredox" -version = "0.1.3" +name = "libc" +version = "0.2.182" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" -dependencies = [ - "bitflags 2.6.0", - "libc", -] +checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" [[package]] -name = "libsecp256k1" -version = "0.6.0" +name = "libm" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9d220bc1feda2ac231cb78c3d26f27676b8cf82c96971f7aeef3d0cf2797c73" -dependencies = [ - "arrayref", - "base64 0.12.3", - "digest 0.9.0", - "hmac-drbg", - "libsecp256k1-core", - "libsecp256k1-gen-ecmult", - "libsecp256k1-gen-genmult", - "rand 0.7.3", - "serde", - "sha2 0.9.9", - "typenum", -] +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" [[package]] -name = "libsecp256k1-core" -version = "0.2.2" +name = "libredox" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0f6ab710cec28cef759c5f18671a27dae2a5f952cdaaee1d8e2908cb2478a80" +checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" dependencies = [ - "crunchy", - "digest 0.9.0", - "subtle", + "bitflags 2.11.0", + "libc", ] [[package]] -name = "libsecp256k1-gen-ecmult" -version = "0.2.1" +name = "linux-raw-sys" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccab96b584d38fac86a83f07e659f0deafd0253dc096dab5a36d53efe653c5c3" -dependencies = [ - "libsecp256k1-core", -] +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" [[package]] -name = "libsecp256k1-gen-genmult" -version = "0.2.1" +name = "litemap" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67abfe149395e3aa1c48a2beb32b068e2334402df8181f818d3aee2b304c4f5d" -dependencies = [ - "libsecp256k1-core", -] +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" [[package]] -name = "light-poseidon" -version = "0.2.0" +name = "lock_api" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c9a85a9752c549ceb7578064b4ed891179d20acd85f27318573b64d2d7ee7ee" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" dependencies = [ - "ark-bn254", - "ark-ff", - "num-bigint 0.4.6", - "thiserror", + "scopeguard", ] [[package]] -name = "linux-raw-sys" -version = "0.4.14" +name = "log" +version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" [[package]] -name = "lock_api" -version = "0.4.12" +name = "lru-slab" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" -dependencies = [ - "autocfg", - "scopeguard", -] +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" [[package]] -name = "log" -version = "0.4.22" +name = "memchr" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[package]] -name = "lz4" -version = "1.26.0" +name = "memoffset" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "958b4caa893816eea05507c20cfe47574a43d9a697138a7872990bba8a0ece68" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" dependencies = [ - "libc", - "lz4-sys", + "autocfg", ] [[package]] -name = "lz4-sys" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "109de74d5d2353660401699a4174a4ff23fcc649caf553df71933c7fb45ad868" -dependencies = [ - "cc", - "libc", -] - -[[package]] -name = "memchr" -version = "2.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" - -[[package]] -name = "memmap2" -version = "0.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" -dependencies = [ - "libc", -] - -[[package]] -name = "memoffset" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" -dependencies = [ - "autocfg", -] - -[[package]] -name = "merlin" -version = "3.0.0" +name = "merlin" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "58c38e2799fc0978b65dfff8023ec7843e2330bb462f19198840b34b6582397d" dependencies = [ @@ -2262,22 +2021,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - -[[package]] -name = "mime_guess" -version = "2.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" -dependencies = [ - "mime", - "unicase", -] - [[package]] name = "minimal-lexical" version = "0.2.1" @@ -2286,114 +2029,43 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.7.4" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ - "adler", + "adler2", + "simd-adler32", ] [[package]] name = "mio" -version = "1.0.1" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4569e456d394deccd22ce1c1913e6ea0e54519f577285001215d33557431afe4" +checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" dependencies = [ - "hermit-abi 0.3.9", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.52.0", -] - -[[package]] -name = "mockall" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c84490118f2ee2d74570d114f3d0493cbf02790df303d2707606c3e14e07c96" -dependencies = [ - "cfg-if", - "downcast", - "fragile", - "lazy_static", - "mockall_derive", - "predicates", - "predicates-tree", + "wasi", + "windows-sys 0.61.2", ] [[package]] -name = "mockall_derive" -version = "0.11.4" +name = "nix" +version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ce75669015c4f47b289fd4d4f56e894e4c96003ffdf3ac51313126f94c6cbb" +checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" dependencies = [ + "bitflags 2.11.0", "cfg-if", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[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 = "multimap" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" - -[[package]] -name = "native-tls" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" -dependencies = [ + "cfg_aliases", "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", + "memoffset", ] [[package]] -name = "never" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c96aba5aa877601bb3f6dd6a63a969e1f82e60646e81e71b14496995e9853c91" - -[[package]] -name = "nix" -version = "0.28.0" +name = "no-std-compat" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" -dependencies = [ - "bitflags 2.6.0", - "cfg-if", - "cfg_aliases 0.1.1", - "libc", - "memoffset", -] +checksum = "b93853da6d84c2e3c7d730d6473e8817692dd89be387eb01b94d7f108ecb5b8c" [[package]] name = "nom" @@ -2406,10 +2078,10 @@ dependencies = [ ] [[package]] -name = "normalize-line-endings" +name = "nonzero_ext" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" +checksum = "38bf9645c8b145698bb0b18a4637dcacbc421ea49bef2317e4fd8065a387cf21" [[package]] name = "num" @@ -2458,9 +2130,9 @@ dependencies = [ [[package]] name = "num-conv" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050" [[package]] name = "num-derive" @@ -2470,7 +2142,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.115", ] [[package]] @@ -2516,48 +2188,34 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" dependencies = [ - "hermit-abi 0.3.9", + "hermit-abi 0.5.2", "libc", ] [[package]] name = "num_enum" -version = "0.7.3" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" +checksum = "b1207a7e20ad57b847bbddc6776b968420d38292bbfe2089accff5e19e82454c" dependencies = [ "num_enum_derive", + "rustversion", ] [[package]] name = "num_enum_derive" -version = "0.7.3" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" +checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7" dependencies = [ - "proc-macro-crate 3.1.0", + "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.72", -] - -[[package]] -name = "number_prefix" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" - -[[package]] -name = "object" -version = "0.36.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f203fa8daa7bb185f760ae12bd8e097f63d17041dcdcaf675ac54cdf863170e" -dependencies = [ - "memchr", + "syn 2.0.115", ] [[package]] @@ -2571,9 +2229,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.19.0" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "opaque-debug" @@ -2581,80 +2239,32 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" -[[package]] -name = "openssl" -version = "0.10.66" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" -dependencies = [ - "bitflags 2.6.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.72", -] - [[package]] name = "openssl-probe" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - -[[package]] -name = "openssl-sys" -version = "0.9.103" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" [[package]] -name = "opentelemetry" -version = "0.17.0" +name = "pairing" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6105e89802af13fdf48c49d7646d3b533a70e536d818aae7e78ba0433d01acb8" +checksum = "81fec4625e73cf41ef4bb6846cafa6d44736525f442ba45e407c4a000a13996f" dependencies = [ - "async-trait", - "crossbeam-channel", - "futures-channel", - "futures-executor", - "futures-util", - "js-sys", - "lazy_static", - "percent-encoding", - "pin-project", - "rand 0.8.5", - "thiserror", + "group", ] [[package]] -name = "os_str_bytes" -version = "6.6.1" +name = "parking" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "parking_lot" -version = "0.12.3" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" dependencies = [ "lock_api", "parking_lot_core", @@ -2662,39 +2272,40 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.10" +version = "0.9.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.3", + "redox_syscall", "smallvec", - "windows-targets 0.52.6", + "windows-link", ] [[package]] -name = "paste" -version = "1.0.15" +name = "pastey" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +checksum = "b867cad97c0791bbd3aaa6472142568c6c9e8f71937e98379f584cfb0cf35bec" [[package]] name = "pbkdf2" -version = "0.4.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "216eaa586a190f0a738f2f918511eecfa90f13295abec0e457cdebcceda80cbd" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" dependencies = [ - "crypto-mac", + "digest", ] [[package]] name = "pbkdf2" -version = "0.11.0" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" dependencies = [ - "digest 0.10.7", + "digest", + "hmac", ] [[package]] @@ -2708,9 +2319,9 @@ dependencies = [ [[package]] name = "percent-encoding" -version = "2.3.1" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "percentage" @@ -2721,41 +2332,11 @@ dependencies = [ "num", ] -[[package]] -name = "petgraph" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" -dependencies = [ - "fixedbitset", - "indexmap 2.3.0", -] - -[[package]] -name = "pin-project" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.72", -] - [[package]] name = "pin-project-lite" -version = "0.2.14" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "pin-utils" @@ -2764,16 +2345,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] -name = "pkg-config" -version = "0.3.30" +name = "pkcs8" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] [[package]] -name = "plain" -version = "0.2.3" +name = "pkg-config" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" [[package]] name = "polyval" @@ -2789,53 +2374,32 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da544ee218f0d287a911e9c99a39a8c9bc8fcad3cb8db5959940044ecfc67265" - -[[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.20" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" -dependencies = [ - "zerocopy", -] +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" [[package]] -name = "predicates" -version = "2.1.5" +name = "potential_utf" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59230a63c37f3e18569bdb90e4a89cbf5bf8b06fea0b84e65ea10cc4df47addd" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" dependencies = [ - "difflib", - "float-cmp", - "itertools 0.10.5", - "normalize-line-endings", - "predicates-core", - "regex", + "zerovec", ] [[package]] -name = "predicates-core" -version = "1.0.8" +name = "powerfmt" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae8177bee8e75d6846599c6b9ff679ed51e882816914eec639944d7c9aa11931" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] -name = "predicates-tree" -version = "1.0.11" +name = "ppv-lite86" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41b740d195ed3166cd147c8047ec98db0e22ec019eb8eeb76d343b795304fb13" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ - "predicates-core", - "termtree", + "zerocopy", ] [[package]] @@ -2846,208 +2410,133 @@ checksum = "c6fa0831dd7cc608c38a5e323422a0077678fa5744aa2be4ad91c4ece8eec8d5" [[package]] name = "prettyplease" -version = "0.1.25" +version = "0.2.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", - "syn 1.0.109", -] - -[[package]] -name = "proc-macro-crate" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" -dependencies = [ - "toml", + "syn 2.0.115", ] [[package]] name = "proc-macro-crate" -version = "3.1.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" dependencies = [ - "toml_edit", + "toml_edit 0.23.10+spec-1.0.0", ] [[package]] -name = "proc-macro-error" -version = "1.0.4" +name = "proc-macro2" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn 1.0.109", - "version_check", + "unicode-ident", ] [[package]] -name = "proc-macro-error-attr" -version = "1.0.4" +name = "qstring" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +checksum = "d464fae65fff2680baf48019211ce37aaec0c78e9264c84a3e484717f965104e" dependencies = [ - "proc-macro2", - "quote", - "version_check", + "percent-encoding", ] [[package]] -name = "proc-macro2" -version = "1.0.86" +name = "quanta" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "f3ab5a9d756f0d97bdc89019bd2e4ea098cf9cde50ee7564dde6b81ccc8f06c7" dependencies = [ - "unicode-ident", + "crossbeam-utils", + "libc", + "once_cell", + "raw-cpuid", + "wasi", + "web-sys", + "winapi", ] [[package]] -name = "prost" +name = "quinn" version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" +checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" dependencies = [ "bytes", - "prost-derive", + "cfg_aliases", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash 2.1.1", + "rustls", + "socket2", + "thiserror 2.0.18", + "tokio", + "tracing", + "web-time", ] [[package]] -name = "prost-build" -version = "0.11.9" +name = "quinn-proto" +version = "0.11.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "119533552c9a7ffacc21e099c24a0ac8bb19c2a2a3f363de84cd9b844feab270" +checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31" dependencies = [ "bytes", - "heck", - "itertools 0.10.5", - "lazy_static", - "log", - "multimap", - "petgraph", - "prettyplease", - "prost", - "prost-types", - "regex", - "syn 1.0.109", - "tempfile", - "which", -] - -[[package]] -name = "prost-derive" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" -dependencies = [ - "anyhow", - "itertools 0.10.5", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "prost-types" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213622a1460818959ac1181aaeb2dc9c7f63df720db7d788b3e24eacd1983e13" -dependencies = [ - "prost", -] - -[[package]] -name = "qstring" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d464fae65fff2680baf48019211ce37aaec0c78e9264c84a3e484717f965104e" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "qualifier_attr" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e2e25ee72f5b24d773cae88422baddefff7714f97aab68d96fe2b6fc4a28fb2" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.72", -] - -[[package]] -name = "quinn" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cc2c5017e4b43d5995dcea317bc46c1e09404c0a9664d2908f7f02dfe943d75" -dependencies = [ - "bytes", - "pin-project-lite", - "quinn-proto", - "quinn-udp", - "rustc-hash", - "rustls", - "thiserror", - "tokio", - "tracing", -] - -[[package]] -name = "quinn-proto" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "141bf7dfde2fbc246bfd3fe12f2455aa24b0fbd9af535d8c86c7bd1381ff2b1a" -dependencies = [ - "bytes", - "rand 0.8.5", - "ring 0.16.20", - "rustc-hash", - "rustls", - "rustls-native-certs", - "slab", - "thiserror", - "tinyvec", - "tracing", + "fastbloom", + "getrandom 0.3.4", + "lru-slab", + "rand 0.9.2", + "ring", + "rustc-hash 2.1.1", + "rustls", + "rustls-pki-types", + "rustls-platform-verifier", + "slab", + "thiserror 2.0.18", + "tinyvec", + "tracing", + "web-time", ] [[package]] name = "quinn-udp" -version = "0.4.1" +version = "0.5.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "055b4e778e8feb9f93c4e439f71dc2156ef13360b432b799e179a8c4cdf0b1d7" +checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" dependencies = [ - "bytes", + "cfg_aliases", "libc", + "once_cell", "socket2", "tracing", - "windows-sys 0.48.0", + "windows-sys 0.60.2", ] [[package]] name = "quote" -version = "1.0.36" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" dependencies = [ "proc-macro2", ] [[package]] -name = "rand" -version = "0.7.3" +name = "r-efi" +version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -dependencies = [ - "getrandom 0.1.16", - "libc", - "rand_chacha 0.2.2", - "rand_core 0.5.1", - "rand_hc", -] +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" [[package]] name = "rand" @@ -3061,13 +2550,13 @@ dependencies = [ ] [[package]] -name = "rand_chacha" -version = "0.2.2" +name = "rand" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ - "ppv-lite86", - "rand_core 0.5.1", + "rand_chacha 0.9.0", + "rand_core 0.9.5", ] [[package]] @@ -3081,12 +2570,13 @@ dependencies = [ ] [[package]] -name = "rand_core" -version = "0.5.1" +name = "rand_chacha" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ - "getrandom 0.1.16", + "ppv-lite86", + "rand_core 0.9.5", ] [[package]] @@ -3095,32 +2585,41 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.17", ] [[package]] -name = "rand_hc" -version = "0.2.0" +name = "rand_core" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" dependencies = [ - "rand_core 0.5.1", + "getrandom 0.3.4", ] [[package]] -name = "rand_xoshiro" -version = "0.6.0" +name = "rand_xorshift" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "raw-cpuid" +version = "11.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "498cd0dc59d73224351ee52a95fee0f1a617a2eae0e7d9d720cc622c73a54186" +dependencies = [ + "bitflags 2.11.0", +] + [[package]] name = "rayon" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" dependencies = [ "either", "rayon-core", @@ -3128,57 +2627,39 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.12.1" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" dependencies = [ "crossbeam-deque", "crossbeam-utils", ] -[[package]] -name = "rc-box" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0690759eabf094030c2cdabc25ade1395bac02210d920d655053c1d49583fd8" -dependencies = [ - "erasable", -] - -[[package]] -name = "redox_syscall" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" -dependencies = [ - "bitflags 1.3.2", -] - [[package]] name = "redox_syscall" -version = "0.5.3" +version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.11.0", ] [[package]] name = "redox_users" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ - "getrandom 0.2.15", + "getrandom 0.2.17", "libredox", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "regex" -version = "1.10.6" +version = "1.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" dependencies = [ "aho-corasick", "memchr", @@ -3188,9 +2669,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.7" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" dependencies = [ "aho-corasick", "memchr", @@ -3199,129 +2680,115 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.4" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +checksum = "a96887878f22d7bad8a3b6dc5b7440e0ada9a245242924394987b21cf2210a4c" [[package]] name = "reqwest" -version = "0.11.27" +version = "0.12.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" +checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" dependencies = [ - "async-compression", - "base64 0.21.7", + "base64 0.22.1", "bytes", - "encoding_rs", + "futures-channel", "futures-core", "futures-util", - "h2", - "http 0.2.12", + "http 1.4.0", "http-body", + "http-body-util", "hyper", "hyper-rustls", - "hyper-tls", - "ipnet", + "hyper-util", "js-sys", "log", - "mime", - "mime_guess", - "native-tls", - "once_cell", "percent-encoding", "pin-project-lite", + "quinn", "rustls", - "rustls-pemfile", + "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", "sync_wrapper", - "system-configuration", "tokio", - "tokio-native-tls", "tokio-rustls", - "tokio-util 0.7.11", + "tower", + "tower-http", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", - "wasm-streams", "web-sys", - "webpki-roots 0.25.4", - "winreg", + "webpki-roots 1.0.6", ] [[package]] name = "reqwest-middleware" -version = "0.2.5" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a735987236a8e238bf0296c7e351b999c188ccc11477f311b82b55c93984216" +checksum = "57f17d28a6e6acfe1733fe24bcd30774d13bffa4b8a22535b4c8c98423088d4e" dependencies = [ "anyhow", "async-trait", - "http 0.2.12", + "http 1.4.0", "reqwest", "serde", - "task-local-extensions", - "thiserror", + "thiserror 1.0.69", + "tower-service", ] [[package]] -name = "ring" -version = "0.16.20" +name = "rfc6979" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" dependencies = [ - "cc", - "libc", - "once_cell", - "spin 0.5.2", - "untrusted 0.7.1", - "web-sys", - "winapi", + "hmac", + "subtle", ] [[package]] name = "ring" -version = "0.17.8" +version = "0.17.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.15", + "getrandom 0.2.17", "libc", - "spin 0.9.8", - "untrusted 0.9.0", + "untrusted", "windows-sys 0.52.0", ] [[package]] name = "rpassword" -version = "7.3.1" +version = "7.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80472be3c897911d0137b2d2b9055faf6eeac5b14e324073d83bc17b191d7e3f" +checksum = "66d4c8b64f049c6721ec8ccec37ddfc3d641c4a7fca57e8f2a89de509c73df39" dependencies = [ "libc", "rtoolbox", - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] name = "rtoolbox" -version = "0.0.2" +version = "0.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c247d24e63230cdb56463ae328478bd5eac8b8faa8c69461a77e8e323afac90e" +checksum = "a7cc970b249fbe527d6e02e0a227762c9108b2f49d81094fe357ffc6d14d7f6f" dependencies = [ "libc", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "rustc-demangle" -version = "0.1.24" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" +checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d" [[package]] name = "rustc-hash" @@ -3329,11 +2796,17 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustc-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" + [[package]] name = "rustc_version" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ "semver", ] @@ -3349,71 +2822,102 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.34" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.11.0", "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] name = "rustls" -version = "0.21.12" +version = "0.23.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" +checksum = "c665f33d38cea657d9614f766881e4d510e0eda4239891eea56b4cadcf01801b" dependencies = [ - "log", - "ring 0.17.8", + "once_cell", + "ring", + "rustls-pki-types", "rustls-webpki", - "sct", + "subtle", + "zeroize", ] [[package]] name = "rustls-native-certs" -version = "0.6.3" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" +checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" dependencies = [ "openssl-probe", - "rustls-pemfile", + "rustls-pki-types", "schannel", "security-framework", ] [[package]] -name = "rustls-pemfile" -version = "1.0.4" +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.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +checksum = "1d99feebc72bae7ab76ba994bb5e121b8d83d910ca40b36e0921f53becc41784" dependencies = [ - "base64 0.21.7", + "core-foundation", + "core-foundation-sys", + "jni", + "log", + "once_cell", + "rustls", + "rustls-native-certs", + "rustls-platform-verifier-android", + "rustls-webpki", + "security-framework", + "security-framework-sys", + "webpki-root-certs", + "windows-sys 0.61.2", ] +[[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" +version = "0.103.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53" dependencies = [ - "ring 0.17.8", - "untrusted 0.9.0", + "ring", + "rustls-pki-types", + "untrusted", ] [[package]] name = "rustversion" -version = "1.0.17" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "ryu" -version = "1.0.18" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" [[package]] name = "same-file" @@ -3426,11 +2930,11 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.23" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -3440,42 +2944,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] -name = "scroll" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04c565b551bafbef4157586fa379538366e4385d42082f255bfd96e4fe8519da" -dependencies = [ - "scroll_derive", -] - -[[package]] -name = "scroll_derive" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1db149f81d46d2deba7cd3c50772474707729550221e69588478ebf9ada425ae" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.72", -] - -[[package]] -name = "sct" -version = "0.7.1" +name = "sec1" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" dependencies = [ - "ring 0.17.8", - "untrusted 0.9.0", + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", ] [[package]] name = "security-framework" -version = "2.11.1" +version = "3.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +checksum = "d17b898a6d6948c3a8ee4372c17cb384f90d2e6e912ef00895b14fd7ab54ec38" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.11.0", "core-foundation", "core-foundation-sys", "libc", @@ -3484,9 +2972,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.11.1" +version = "2.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75da29fe9b9b08fe9d6b22b5b4bcbc75d8db3aa31e639aa56bb62e9d46bfceaf" +checksum = "321c8673b092a9a42605034a9879d73cb79101ed5fd117bc9a597b89b4e9e61a" dependencies = [ "core-foundation-sys", "libc", @@ -3494,57 +2982,78 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.23" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" [[package]] -name = "seqlock" -version = "0.2.0" +name = "serde" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5c67b6f14ecc5b86c66fa63d76b5092352678545a8a3cdae80aef5128371910" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ - "parking_lot", + "serde_core", + "serde_derive", ] [[package]] -name = "serde" -version = "1.0.204" +name = "serde-big-array" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" +checksum = "11fc7cc2c76d73e0f27ee52abbd64eec84d46f370c88371120433196934e4b7f" dependencies = [ - "serde_derive", + "serde", ] [[package]] name = "serde_bytes" -version = "0.11.15" +version = "0.11.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "387cc504cb06bb40a96c8e04e951fe01854cf6bc921053c954e4a606d9675c6a" +checksum = "a5d440709e79d88e51ac01c4b72fc6cb7314017bb7da9eeff678aa94c10e3ea8" dependencies = [ "serde", + "serde_core", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.204" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.115", ] [[package]] name = "serde_json" -version = "1.0.122" +version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784b6203951c57ff748476b126ccb5e8e2959a5c19e5c617ab1956be3dbc68da" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ "itoa", "memchr", - "ryu", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_spanned" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +dependencies = [ "serde", ] @@ -3562,36 +3071,24 @@ dependencies = [ [[package]] name = "serde_with" -version = "2.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07ff71d2c147a7b57362cead5e22f772cd52f6ab31cfcd9edcd7f6aeb2a0afbe" -dependencies = [ - "serde", - "serde_with_macros 2.3.3", -] - -[[package]] -name = "serde_with_macros" -version = "1.5.2" +version = "3.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082" +checksum = "4fa237f2807440d238e0364a218270b98f767a00d3dada77b1c53ae88940e2e7" dependencies = [ - "darling 0.13.4", - "proc-macro2", - "quote", - "syn 1.0.109", + "serde_core", + "serde_with_macros", ] [[package]] name = "serde_with_macros" -version = "2.3.3" +version = "3.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "881b6f881b17d13214e5d494c939ebab463d01264ce1811e9d4ac3a882e7695f" +checksum = "52a8e3ca0ca629121f70ab50f95249e5a6f925cc0f6ffe8256c45b728875706c" dependencies = [ - "darling 0.20.10", + "darling", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.115", ] [[package]] @@ -3600,7 +3097,7 @@ version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap 2.3.0", + "indexmap", "itoa", "ryu", "serde", @@ -3615,44 +3112,25 @@ checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", "cpufeatures", - "digest 0.10.7", + "digest", ] [[package]] name = "sha2" -version = "0.9.9" +version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ - "block-buffer 0.9.0", "cfg-if", "cpufeatures", - "digest 0.9.0", - "opaque-debug", -] - -[[package]] -name = "sha2" -version = "0.10.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest 0.10.7", + "digest", ] [[package]] -name = "sha3" -version = "0.9.1" +name = "sha2-const-stable" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f81199417d4e5de3f04b1e871023acea7389672c4135918f05aa9cbf2f2fa809" -dependencies = [ - "block-buffer 0.9.0", - "digest 0.9.0", - "keccak", - "opaque-debug", -] +checksum = "5f179d4e11094a893b82fff208f74d448a7512f99f5a0acbd5c679b705f83ed9" [[package]] name = "sha3" @@ -3660,70 +3138,71 @@ version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" dependencies = [ - "digest 0.10.7", + "digest", "keccak", ] [[package]] -name = "sharded-slab" -version = "0.1.7" +name = "shell-words" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" -dependencies = [ - "lazy_static", -] +checksum = "dc6fe69c597f9c37bfeeeeeb33da3530379845f10be461a66d16d03eca2ded77" [[package]] -name = "shell-words" -version = "1.1.0" +name = "shlex" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook-registry" -version = "1.4.2" +version = "1.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" dependencies = [ + "errno", "libc", ] [[package]] name = "signature" -version = "1.6.4" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core 0.6.4", +] [[package]] -name = "siphasher" +name = "simd-adler32" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" + +[[package]] +name = "siphasher" version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" [[package]] -name = "sized-chunks" -version = "0.6.5" +name = "siphasher" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16d69225bde7a69b235da73377861095455d298f2b970996eec25ddbb42b3d1e" -dependencies = [ - "bitmaps", - "typenum", -] +checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e" [[package]] name = "slab" -version = "0.4.9" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "smallvec" -version = "1.13.2" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "sniper" @@ -3731,232 +3210,277 @@ version = "0.1.0" dependencies = [ "arrayref", "base64 0.22.1", - "borsh 1.5.1", + "borsh", "bs58", "byteorder", "chrono", - "colored 2.1.0", - "dotenv", + "colored 2.2.0", "fern", "futures", "futures-util", "log", - "regex", - "reqwest", "serde", "serde_json", "solana-account-decoder", "solana-client", + "solana-commitment-config", + "solana-compute-budget-interface", "solana-sdk", + "solana-system-interface 3.0.0", "solana-transaction-status", "spl-associated-token-account", "spl-token", "spl-token-client", - "teloxide", "tokio", - "tokio-tungstenite 0.21.0", + "toml", + "trait-variant", ] [[package]] name = "socket2" -version = "0.5.7" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.60.2", +] + +[[package]] +name = "solana-account" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efc0ed36decb689413b9da5d57f2be49eea5bebb3cf7897015167b0c4336e731" +dependencies = [ + "bincode", + "serde", + "serde_bytes", + "serde_derive", + "solana-account-info", + "solana-clock", + "solana-instruction-error", + "solana-pubkey 4.1.0", + "solana-sdk-ids", + "solana-sysvar", ] [[package]] name = "solana-account-decoder" -version = "2.0.4" +version = "3.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a919e80186d23cc4cda95ce7d11d895edf06ac31d56ab44eafb8b22a44c5015" +checksum = "66939b3e7aa0fab7a523bbb0d0518e3cdbb6a9b8675d5ae3a7bba5c1bef98622" dependencies = [ "Inflector", "base64 0.22.1", "bincode", "bs58", "bv", - "lazy_static", "serde", - "serde_derive", "serde_json", - "solana-config-program", - "solana-sdk", - "spl-token", - "spl-token-2022", + "solana-account", + "solana-account-decoder-client-types", + "solana-address-lookup-table-interface", + "solana-clock", + "solana-config-interface", + "solana-epoch-schedule", + "solana-fee-calculator", + "solana-instruction", + "solana-loader-v3-interface", + "solana-nonce", + "solana-program-option", + "solana-program-pack", + "solana-pubkey 3.0.0", + "solana-rent", + "solana-sdk-ids", + "solana-slot-hashes", + "solana-slot-history", + "solana-stake-interface", + "solana-sysvar", + "solana-vote-interface", + "spl-generic-token", + "spl-token-2022-interface", "spl-token-group-interface", + "spl-token-interface", "spl-token-metadata-interface", - "thiserror", + "thiserror 2.0.18", "zstd", ] [[package]] -name = "solana-accounts-db" -version = "2.0.4" +name = "solana-account-decoder-client-types" +version = "3.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bcf86e96f5e986687edc572033df43723b885c668fa1a3280753232dc8f3656" +dependencies = [ + "base64 0.22.1", + "bs58", + "serde", + "serde_json", + "solana-account", + "solana-pubkey 3.0.0", + "zstd", +] + +[[package]] +name = "solana-account-info" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "342fc66d5df0093bbad7eb775a3d5ff52f1585bb369ec15b6273cd6806223bd3" +checksum = "fc3397241392f5756925029acaa8515dc70fcbe3d8059d4885d7d6533baf64fd" dependencies = [ "bincode", - "blake3", - "bv", + "serde_core", + "solana-address 2.2.0", + "solana-program-error", + "solana-program-memory", +] + +[[package]] +name = "solana-address" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2ecac8e1b7f74c2baa9e774c42817e3e75b20787134b76cc4d45e8a604488f5" +dependencies = [ + "solana-address 2.2.0", +] + +[[package]] +name = "solana-address" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68c5d02824391b072dc5cd0aaa85fb0af9784a21d23286a767994d1e8a322131" +dependencies = [ + "borsh", "bytemuck", "bytemuck_derive", - "bzip2", - "crossbeam-channel", - "dashmap", - "index_list", - "indexmap 2.3.0", - "itertools 0.12.1", - "lazy_static", - "log", - "lz4", - "memmap2", - "modular-bitfield", - "num_cpus", - "num_enum", - "rand 0.8.5", - "rayon", - "rustc_version", - "seqlock", + "curve25519-dalek", + "five8", + "five8_const", + "rand 0.9.2", "serde", "serde_derive", - "smallvec", - "solana-bucket-map", - "solana-inline-spl", - "solana-measure", - "solana-metrics", - "solana-nohash-hasher", - "solana-rayon-threadlimit", - "solana-sdk", - "solana-svm", - "static_assertions", - "tar", - "tempfile", - "thiserror", + "sha2-const-stable", + "solana-atomic-u64", + "solana-define-syscall 5.0.0", + "solana-program-error", + "solana-sanitize", + "solana-sha256-hasher", + "wincode", ] [[package]] -name = "solana-address-lookup-table-program" -version = "2.0.4" +name = "solana-address-lookup-table-interface" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5827bf8a4941ae49f7c9b8c8c06491fb40128ce589c696ff4e2eb72043005655" +checksum = "5e8df0b083c10ce32490410f3795016b1b5d9b4d094658c0a5e496753645b7cd" dependencies = [ "bincode", "bytemuck", - "log", - "num-derive", - "num-traits", - "rustc_version", - "solana-program", - "solana-program-runtime", - "solana-sdk", - "thiserror", + "serde", + "serde_derive", + "solana-clock", + "solana-instruction", + "solana-instruction-error", + "solana-pubkey 4.1.0", + "solana-sdk-ids", + "solana-slot-hashes", ] [[package]] -name = "solana-banks-client" -version = "2.0.4" +name = "solana-atomic-u64" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3045f5b0bdb3d37b0e06fbe7ed8950f0320dd7cfa62e0f054227b52b179a8f4f" +checksum = "a933ff1e50aff72d02173cfcd7511bd8540b027ee720b75f353f594f834216d0" dependencies = [ - "borsh 1.5.1", - "futures", - "solana-banks-interface", - "solana-program", - "solana-sdk", - "tarpc", - "thiserror", - "tokio", - "tokio-serde", + "parking_lot", ] [[package]] -name = "solana-banks-interface" -version = "2.0.4" +name = "solana-big-mod-exp" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d8ec664173cb39ac3bb6181cf32da2c89064057b65d0252cc9548b5674a6dbf" +checksum = "30c80fb6d791b3925d5ec4bf23a7c169ef5090c013059ec3ed7d0b2c04efa085" dependencies = [ - "serde", - "serde_derive", - "solana-sdk", - "tarpc", + "num-bigint 0.4.6", + "num-traits", + "solana-define-syscall 3.0.0", ] [[package]] -name = "solana-banks-server" -version = "2.0.4" +name = "solana-bincode" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b682da23ea1902c792c1ed74aeaf9d6bb3331eabfbd353efb8e483fae9825ddf" +checksum = "278a1a5bad62cd9da89ac8d4b7ec444e83caa8ae96aa656dfc27684b28d49a5d" dependencies = [ "bincode", - "crossbeam-channel", - "futures", - "solana-banks-interface", - "solana-client", - "solana-runtime", - "solana-sdk", - "solana-send-transaction-service", - "solana-svm", - "tarpc", - "tokio", - "tokio-serde", + "serde_core", + "solana-instruction-error", ] [[package]] -name = "solana-bpf-loader-program" -version = "2.0.4" +name = "solana-blake3-hasher" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f5fc44e1b0c58c5c625c95f8cea93e392dddfe3564718070a7f6c3e44ee174b" +checksum = "7116e1d942a2432ca3f514625104757ab8a56233787e95144c93950029e31176" dependencies = [ - "bincode", - "byteorder", - "libsecp256k1", - "log", - "scopeguard", - "solana-compute-budget", - "solana-curve25519", - "solana-measure", - "solana-poseidon", - "solana-program-runtime", - "solana-sdk", - "solana-type-overrides", - "solana_rbpf", - "thiserror", + "blake3", + "solana-define-syscall 4.0.1", + "solana-hash 4.2.0", ] [[package]] -name = "solana-bucket-map" -version = "2.0.4" +name = "solana-bls-signatures" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef47e5ee080d8c6f1496fd0c5b33fcacdded8e8511e401234235d496197a4c1d" +checksum = "61c75573697bbb148afa8209aa3ce228ca0754584c9a8a91e818db0f706ae4fb" dependencies = [ - "bv", - "bytemuck", - "bytemuck_derive", - "log", - "memmap2", - "modular-bitfield", - "num_enum", + "base64 0.22.1", + "blst", + "blstrs", + "cfg_eval", + "ff", + "group", + "pairing", "rand 0.8.5", - "solana-measure", - "solana-sdk", - "tempfile", + "serde", + "serde_json", + "serde_with", + "thiserror 2.0.18", +] + +[[package]] +name = "solana-borsh" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc402b16657abbfa9991cd5cbfac5a11d809f7e7d28d3bb291baeb088b39060e" +dependencies = [ + "borsh", ] [[package]] name = "solana-clap-utils" -version = "2.0.4" +version = "3.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afd53ffd6165a342899f1b4a0556fb4e2831cbee18c8b63c9779344ba3cdea14" +checksum = "f1a2875a1d148c9f356c4dc237681cb66b504cbe431ca468f1ec587173a3d416" dependencies = [ "chrono", - "clap 2.34.0", + "clap", "rpassword", + "solana-bls-signatures", + "solana-clock", + "solana-cluster-type", + "solana-commitment-config", + "solana-derivation-path", + "solana-hash 3.1.0", + "solana-keypair", + "solana-message", + "solana-native-token", + "solana-presigner", + "solana-pubkey 3.0.0", "solana-remote-wallet", - "solana-sdk", - "thiserror", + "solana-seed-phrase", + "solana-signature", + "solana-signer", + "thiserror 2.0.18", "tiny-bip39", "uriparse", "url", @@ -3964,475 +3488,956 @@ dependencies = [ [[package]] name = "solana-cli-config" -version = "2.0.4" +version = "3.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11ad0c0a30fb58383690b85da636a45b947d2237722477c73bbb39e05ad992de" +checksum = "70215cf542074daf7d2c60241f018574fdc01add7af8c57254a84fd40525fc82" dependencies = [ "dirs-next", - "lazy_static", "serde", - "serde_derive", "serde_yaml", "solana-clap-utils", - "solana-sdk", + "solana-commitment-config", "url", ] [[package]] name = "solana-cli-output" -version = "2.0.4" +version = "3.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16e998f959bdedc994f8b17c72206c4234dec2ec4a6d0feb8c460ad4ffb92051" +checksum = "c75b9c6f7b0ab8617eb03b22c78b860af588f6f1bc76c5ada6b8125a9826b4c8" dependencies = [ "Inflector", + "agave-reserved-account-keys", "base64 0.22.1", "chrono", - "clap 2.34.0", - "console", + "clap", + "console 0.16.2", "humantime", "indicatif", "pretty-hex", "semver", "serde", "serde_json", + "solana-account", "solana-account-decoder", + "solana-bincode", "solana-clap-utils", "solana-cli-config", + "solana-clock", + "solana-epoch-info", + "solana-hash 3.1.0", + "solana-message", + "solana-packet", + "solana-pubkey 3.0.0", "solana-rpc-client-api", - "solana-sdk", + "solana-sdk-ids", + "solana-signature", + "solana-stake-interface", + "solana-system-interface 2.0.0", + "solana-transaction", + "solana-transaction-error", "solana-transaction-status", + "solana-transaction-status-client-types", "solana-vote-program", - "spl-memo", + "spl-memo-interface", ] [[package]] name = "solana-client" -version = "2.0.4" +version = "3.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adaf07dc10394a8bfc5d96da9c10de12e5f3104a8d84eb0990d0a30cca876192" +checksum = "061e7290051a639e0efe8078b6c8c7ebe99d13f56ee651b93c0529fba012b99d" dependencies = [ "async-trait", "bincode", "dashmap", "futures", "futures-util", - "indexmap 2.3.0", + "indexmap", "indicatif", "log", "quinn", "rayon", + "solana-account", + "solana-client-traits", + "solana-commitment-config", "solana-connection-cache", + "solana-epoch-info", + "solana-hash 3.1.0", + "solana-instruction", + "solana-keypair", "solana-measure", - "solana-metrics", + "solana-message", + "solana-net-utils", + "solana-pubkey 3.0.0", "solana-pubsub-client", "solana-quic-client", + "solana-quic-definitions", "solana-rpc-client", "solana-rpc-client-api", "solana-rpc-client-nonce-utils", - "solana-sdk", + "solana-signature", + "solana-signer", "solana-streamer", - "solana-thin-client", + "solana-time-utils", "solana-tpu-client", + "solana-transaction", + "solana-transaction-error", + "solana-transaction-status-client-types", "solana-udp-client", - "thiserror", + "thiserror 2.0.18", "tokio", + "tokio-util", ] [[package]] -name = "solana-compute-budget" -version = "2.0.4" +name = "solana-client-traits" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af98c3bec3b3c8581ca6f92662e71442f763623044722a311eaa177ab4e9d370" +checksum = "08618ed587e128105510c54ae3e456b9a06d674d8640db75afe66dad65cb4e02" dependencies = [ - "rustc_version", - "solana-sdk", + "solana-account", + "solana-commitment-config", + "solana-epoch-info", + "solana-hash 3.1.0", + "solana-instruction", + "solana-keypair", + "solana-message", + "solana-pubkey 3.0.0", + "solana-signature", + "solana-signer", + "solana-system-interface 2.0.0", + "solana-transaction", + "solana-transaction-error", ] [[package]] -name = "solana-compute-budget-program" -version = "2.0.4" +name = "solana-clock" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c49e03b08a7559f1cfa23b90dc71f3625a33a4b8a62435a5254776d94e27dd" +checksum = "fb62e9381182459a4520b5fe7fb22d423cae736239a6427fc398a88743d0ed59" dependencies = [ - "solana-program-runtime", - "solana-sdk", + "serde", + "serde_derive", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-sysvar-id", ] [[package]] -name = "solana-config-program" -version = "2.0.4" +name = "solana-cluster-type" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb7692fa6bf10a1a86b450c4775526f56d7e0e2116a53313f2533b5694abea64" +dependencies = [ + "solana-hash 3.1.0", +] + +[[package]] +name = "solana-commitment-config" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e41a3917076a8b5375809078ae3a6fb76a53e364b596ef8c4265e7f410876f3" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "solana-compute-budget-interface" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8292c436b269ad23cecc8b24f7da3ab07ca111661e25e00ce0e1d22771951ab9" +dependencies = [ + "solana-instruction", + "solana-sdk-ids", +] + +[[package]] +name = "solana-config-interface" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4c5011c9b46bef0174c048bf3acaf93b97b3d08ec23f7c0c452cdfffeb2c0b1" +checksum = "63e401ae56aed512821cc7a0adaa412ff97fecd2dff4602be7b1330d2daec0c4" dependencies = [ "bincode", - "chrono", "serde", "serde_derive", - "solana-program-runtime", - "solana-sdk", + "solana-account", + "solana-instruction", + "solana-pubkey 3.0.0", + "solana-sdk-ids", + "solana-short-vec", + "solana-system-interface 2.0.0", ] [[package]] name = "solana-connection-cache" -version = "2.0.4" +version = "3.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53ec898696a0ab5538238f0ecb1184b7cf49711800602e0e2dd060a5367c3293" +checksum = "f0cf8656543f9c391b1fd06397038c1586162cbd4630274580cfc0993388b3ae" dependencies = [ "async-trait", "bincode", "crossbeam-channel", "futures-util", - "indexmap 2.3.0", + "indexmap", "log", "rand 0.8.5", "rayon", + "solana-keypair", "solana-measure", "solana-metrics", - "solana-sdk", - "thiserror", + "solana-time-utils", + "solana-transaction-error", + "thiserror 2.0.18", "tokio", ] [[package]] -name = "solana-cost-model" -version = "2.0.4" +name = "solana-cpi" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87beb0e358a381c9cc57d546104b9f4fa65489236bd0909528794e7e08be6b80" +checksum = "4dea26709d867aada85d0d3617db0944215c8bb28d3745b912de7db13a23280c" dependencies = [ - "ahash", - "lazy_static", - "log", - "rustc_version", - "solana-address-lookup-table-program", - "solana-bpf-loader-program", - "solana-compute-budget", - "solana-compute-budget-program", - "solana-config-program", - "solana-loader-v4-program", - "solana-metrics", - "solana-sdk", - "solana-stake-program", - "solana-system-program", - "solana-vote-program", + "solana-account-info", + "solana-define-syscall 4.0.1", + "solana-instruction", + "solana-program-error", + "solana-pubkey 4.1.0", + "solana-stable-layout", ] [[package]] name = "solana-curve25519" -version = "2.0.4" +version = "3.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a7a7e9bc903aa73b077e6c26d2871ef8a28b5c7914adb405d56106fbe6e2e09" +checksum = "737ede9143c36b8628cc11d920cdb762cd1ccbd7ca904c3bd63b39c58669fe38" dependencies = [ "bytemuck", "bytemuck_derive", "curve25519-dalek", - "solana-program", - "thiserror", + "solana-define-syscall 3.0.0", + "subtle", + "thiserror 2.0.18", ] [[package]] -name = "solana-inline-spl" -version = "2.0.4" +name = "solana-define-syscall" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "193b8c147432d12bd38ec5a88e9ebd63b2b2f12d293ea8c0f729d879da2912fc" -dependencies = [ - "bytemuck", - "rustc_version", - "solana-sdk", -] +checksum = "f9697086a4e102d28a156b8d6b521730335d6951bd39a5e766512bbe09007cee" [[package]] -name = "solana-loader-v4-program" -version = "2.0.4" +name = "solana-define-syscall" +version = "4.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7f01ea20f9994cb976e082b4b8c8350f1afc7b6558ce2cc3533f2bd68aa3f23" -dependencies = [ - "log", - "solana-compute-budget", - "solana-measure", - "solana-program-runtime", - "solana-sdk", - "solana-type-overrides", - "solana_rbpf", -] +checksum = "57e5b1c0bc1d4a4d10c88a4100499d954c09d3fecfae4912c1a074dff68b1738" [[package]] -name = "solana-logger" -version = "2.0.4" +name = "solana-define-syscall" +version = "5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a13451d8cf9e6f07075d3463a52cf582f26721572c7c116619df8f644b086c3c" -dependencies = [ - "env_logger", - "lazy_static", - "log", -] +checksum = "03aacdd7a61e2109887a7a7f046caebafce97ddf1150f33722eeac04f9039c73" [[package]] -name = "solana-measure" -version = "2.0.4" +name = "solana-derivation-path" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37a30cf602267aa8db1bc22c8f69621ff9eec707407167a9566d6b845494b658" +checksum = "ff71743072690fdbdfcdc37700ae1cb77485aaad49019473a81aee099b1e0b8c" dependencies = [ - "log", - "solana-sdk", + "derivation-path", + "qstring", + "uriparse", ] [[package]] -name = "solana-metrics" -version = "2.0.4" +name = "solana-epoch-info" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a2de421155828699e15794ad4eb14edf50192e25e73648f0d8ae41826d4169e" +checksum = "e093c84f6ece620a6b10cd036574b0cd51944231ab32d81f80f76d54aba833e6" dependencies = [ - "crossbeam-channel", - "gethostname", - "lazy_static", - "log", - "reqwest", - "solana-sdk", - "thiserror", + "serde", + "serde_derive", ] [[package]] -name = "solana-net-utils" -version = "2.0.4" +name = "solana-epoch-rewards" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1639aeacd8725cfba196e062a68a0568d04b2458d42d9cdeead987a96743d2c5" +checksum = "b319a4ed70390af911090c020571f0ff1f4ec432522d05ab89f5c08080381995" dependencies = [ - "bincode", - "clap 3.2.25", - "crossbeam-channel", - "log", - "nix", - "rand 0.8.5", "serde", "serde_derive", - "socket2", - "solana-logger", - "solana-sdk", - "solana-version", - "static_assertions", - "tokio", - "url", + "solana-hash 3.1.0", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-sysvar-id", ] [[package]] -name = "solana-nohash-hasher" -version = "0.2.1" +name = "solana-epoch-rewards-hasher" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b8a731ed60e89177c8a7ab05fe0f1511cedd3e70e773f288f9de33a9cfdc21e" +checksum = "1ee8beac9bff4db9225e57d532d169b0be5e447f1e6601a2f50f27a01bf5518f" +dependencies = [ + "siphasher 0.3.11", + "solana-address 2.2.0", + "solana-hash 4.2.0", +] + +[[package]] +name = "solana-epoch-schedule" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e5481e72cc4d52c169db73e4c0cd16de8bc943078aac587ec4817a75cc6388f" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-sysvar-id", +] + +[[package]] +name = "solana-epoch-stake" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc6693d0ea833b880514b9b88d95afb80b42762dca98b0712465d1fcbbcb89e" +dependencies = [ + "solana-define-syscall 3.0.0", + "solana-pubkey 3.0.0", +] + +[[package]] +name = "solana-example-mocks" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978855d164845c1b0235d4b4d101cadc55373fffaf0b5b6cfa2194d25b2ed658" +dependencies = [ + "serde", + "serde_derive", + "solana-address-lookup-table-interface", + "solana-clock", + "solana-hash 3.1.0", + "solana-instruction", + "solana-keccak-hasher", + "solana-message", + "solana-nonce", + "solana-pubkey 3.0.0", + "solana-sdk-ids", + "solana-system-interface 2.0.0", + "thiserror 2.0.18", +] + +[[package]] +name = "solana-feature-gate-interface" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75ca9b5cbb6f500f7fd73db5bd95640f71a83f04d6121a0e59a43b202dca2731" +dependencies = [ + "serde", + "serde_derive", + "solana-program-error", + "solana-pubkey 4.1.0", + "solana-sdk-ids", +] + +[[package]] +name = "solana-fee-calculator" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b2a5675b2cf8d407c672dc1776492b1f382337720ddf566645ae43237a3d8c3" +dependencies = [ + "log", + "serde", + "serde_derive", +] + +[[package]] +name = "solana-fee-structure" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e2abdb1223eea8ec64136f39cb1ffcf257e00f915c957c35c0dd9e3f4e700b0" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "solana-hard-forks" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0abacc4b66ce471f135f48f22facf75cbbb0f8a252fbe2c1e0aa59d5b203f519" + +[[package]] +name = "solana-hash" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "337c246447142f660f778cf6cb582beba8e28deb05b3b24bfb9ffd7c562e5f41" +dependencies = [ + "solana-hash 4.2.0", +] + +[[package]] +name = "solana-hash" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8064ea1d591ec791be95245058ca40f4f5345d390c200069d0f79bbf55bfae55" +dependencies = [ + "borsh", + "bytemuck", + "bytemuck_derive", + "five8", + "serde", + "serde_derive", + "solana-atomic-u64", + "solana-sanitize", + "wincode", +] + +[[package]] +name = "solana-inflation" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e92f37a14e7c660628752833250dd3dcd8e95309876aee751d7f8769a27947c6" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "solana-instruction" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee1b699a2c1518028a9982e255e0eca10c44d90006542d9d7f9f40dbce3f7c78" +dependencies = [ + "bincode", + "borsh", + "serde", + "serde_derive", + "solana-define-syscall 4.0.1", + "solana-instruction-error", + "solana-pubkey 4.1.0", +] + +[[package]] +name = "solana-instruction-error" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b04259e03c05faf38a8c24217b5cfe4c90572ae6184ab49cddb1584fdd756d3f" +dependencies = [ + "num-traits", + "serde", + "serde_derive", + "solana-program-error", +] + +[[package]] +name = "solana-instructions-sysvar" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ddf67876c541aa1e21ee1acae35c95c6fbc61119814bfef70579317a5e26955" +dependencies = [ + "bitflags 2.11.0", + "solana-account-info", + "solana-instruction", + "solana-instruction-error", + "solana-program-error", + "solana-pubkey 3.0.0", + "solana-sanitize", + "solana-sdk-ids", + "solana-serialize-utils", + "solana-sysvar-id", +] + +[[package]] +name = "solana-keccak-hasher" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed1c0d16d6fdeba12291a1f068cdf0d479d9bff1141bf44afd7aa9d485f65ef8" +dependencies = [ + "sha3", + "solana-define-syscall 4.0.1", + "solana-hash 4.2.0", +] + +[[package]] +name = "solana-keypair" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ac8be597c9e231b0cab2928ce3bc3e4ee77d9c0ad92977b9d901f3879f25a7a" +dependencies = [ + "ed25519-dalek", + "ed25519-dalek-bip32", + "five8", + "rand 0.8.5", + "solana-address 2.2.0", + "solana-derivation-path", + "solana-seed-derivable", + "solana-seed-phrase", + "solana-signature", + "solana-signer", +] + +[[package]] +name = "solana-last-restart-slot" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcda154ec827f5fc1e4da0af3417951b7e9b8157540f81f936c4a8b1156134d0" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-sysvar-id", +] + +[[package]] +name = "solana-loader-v2-interface" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e4a6f0ad4fd9c30679bfee2ce3ea6a449cac38049f210480b751f65676dfe82" +dependencies = [ + "serde", + "serde_bytes", + "serde_derive", + "solana-instruction", + "solana-pubkey 3.0.0", + "solana-sdk-ids", +] + +[[package]] +name = "solana-loader-v3-interface" +version = "6.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dee44c9b1328c5c712c68966fb8de07b47f3e7bac006e74ddd1bb053d3e46e5d" +dependencies = [ + "serde", + "serde_bytes", + "serde_derive", + "solana-instruction", + "solana-pubkey 3.0.0", + "solana-sdk-ids", + "solana-system-interface 2.0.0", +] + +[[package]] +name = "solana-measure" +version = "3.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be8c8288f2b0755aaec2bae772239a48408e076a9b90db40c936f1fa5debbc78" + +[[package]] +name = "solana-message" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0448b1fd891c5f46491e5dc7d9986385ba3c852c340db2911dd29faa01d2b08d" +dependencies = [ + "bincode", + "blake3", + "lazy_static", + "serde", + "serde_derive", + "solana-address 2.2.0", + "solana-hash 4.2.0", + "solana-instruction", + "solana-sanitize", + "solana-sdk-ids", + "solana-short-vec", + "solana-transaction-error", +] + +[[package]] +name = "solana-metrics" +version = "3.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dac53c2ae91e227cd1f0aa9f744beca638a2e971b84d7c2f008cf2c75af1b0d5" +dependencies = [ + "crossbeam-channel", + "gethostname", + "log", + "reqwest", + "solana-cluster-type", + "solana-sha256-hasher", + "solana-time-utils", + "thiserror 2.0.18", +] + +[[package]] +name = "solana-msg" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "264275c556ea7e22b9d3f87d56305546a38d4eee8ec884f3b126236cb7dcbbb4" +dependencies = [ + "solana-define-syscall 3.0.0", +] + +[[package]] +name = "solana-native-token" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae8dd4c280dca9d046139eb5b7a5ac9ad10403fbd64964c7d7571214950d758f" + +[[package]] +name = "solana-net-utils" +version = "3.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23848218da169349b400780ee5d8d683792304115d4b675f0d9e0b8949433eb2" +dependencies = [ + "anyhow", + "bincode", + "bytes", + "cfg-if", + "dashmap", + "itertools", + "log", + "nix", + "rand 0.8.5", + "serde", + "socket2", + "solana-serde", + "solana-svm-type-overrides", + "tokio", + "url", +] + +[[package]] +name = "solana-nonce" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbc469152a63284ef959b80c59cda015262a021da55d3b8fe42171d89c4b64f8" +dependencies = [ + "serde", + "serde_derive", + "solana-fee-calculator", + "solana-hash 4.2.0", + "solana-pubkey 4.1.0", + "solana-sha256-hasher", +] + +[[package]] +name = "solana-offchain-message" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6e2a1141a673f72a05cf406b99e4b2b8a457792b7c01afa07b3f00d4e2de393" +dependencies = [ + "num_enum", + "solana-hash 3.1.0", + "solana-packet", + "solana-pubkey 3.0.0", + "solana-sanitize", + "solana-sha256-hasher", + "solana-signature", + "solana-signer", +] + +[[package]] +name = "solana-packet" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6edf2f25743c95229ac0fdc32f8f5893ef738dbf332c669e9861d33ddb0f469d" +dependencies = [ + "bincode", + "bitflags 2.11.0", + "cfg_eval", + "serde", + "serde_derive", + "serde_with", +] [[package]] name = "solana-perf" -version = "2.0.4" +version = "3.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ad8287c657a5b6c5ec2f72c8f78ef614b000a1536d3269394ef26c6b5e35ea1" +checksum = "87608537c53ca0976f04166691fc11523e93802a50660b719e62e172dd47cf10" dependencies = [ "ahash", "bincode", "bv", + "bytes", "caps", "curve25519-dalek", "dlopen2", "fnv", - "lazy_static", "libc", "log", "nix", "rand 0.8.5", "rayon", - "rustc_version", "serde", + "solana-hash 3.1.0", + "solana-message", "solana-metrics", + "solana-packet", + "solana-pubkey 3.0.0", "solana-rayon-threadlimit", - "solana-sdk", - "solana-vote-program", + "solana-sdk-ids", + "solana-short-vec", + "solana-signature", + "solana-time-utils", + "solana-transaction-context", ] [[package]] -name = "solana-poseidon" -version = "2.0.4" +name = "solana-precompile-error" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cafcd950de74c6c39d55dc8ca108bbb007799842ab370ef26cf45a34453c31e1" +dependencies = [ + "num-traits", +] + +[[package]] +name = "solana-presigner" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "460872e25ce4cf76fad7a963d257bc1e707b636db36cc230d4cdbd64f48f4193" +checksum = "0f704eaf825be3180832445b9e4983b875340696e8e7239bf2d535b0f86c14a2" dependencies = [ - "ark-bn254", - "light-poseidon", - "thiserror", + "solana-pubkey 3.0.0", + "solana-signature", + "solana-signer", ] [[package]] name = "solana-program" -version = "2.0.4" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c75b255c34423a56d35bf695ada268d15112f782771f2a0ad12f28b5fb07cd3" +checksum = "91b12305dd81045d705f427acd0435a2e46444b65367d7179d7bdcfc3bc5f5eb" dependencies = [ - "ark-bn254", - "ark-ec", - "ark-ff", - "ark-serialize", - "base64 0.22.1", - "bincode", - "bitflags 2.6.0", - "blake3", - "borsh 0.10.3", - "borsh 1.5.1", - "bs58", - "bv", - "bytemuck", - "bytemuck_derive", - "console_error_panic_hook", - "console_log", - "curve25519-dalek", - "getrandom 0.2.15", - "js-sys", - "lazy_static", - "libsecp256k1", - "log", "memoffset", - "num-bigint 0.4.6", - "num-derive", - "num-traits", - "parking_lot", - "rand 0.8.5", - "rustc_version", - "rustversion", + "solana-account-info", + "solana-big-mod-exp", + "solana-blake3-hasher", + "solana-borsh", + "solana-clock", + "solana-cpi", + "solana-define-syscall 3.0.0", + "solana-epoch-rewards", + "solana-epoch-schedule", + "solana-epoch-stake", + "solana-example-mocks", + "solana-fee-calculator", + "solana-hash 3.1.0", + "solana-instruction", + "solana-instruction-error", + "solana-instructions-sysvar", + "solana-keccak-hasher", + "solana-last-restart-slot", + "solana-msg", + "solana-native-token", + "solana-program-entrypoint", + "solana-program-error", + "solana-program-memory", + "solana-program-option", + "solana-program-pack", + "solana-pubkey 3.0.0", + "solana-rent", + "solana-sdk-ids", + "solana-secp256k1-recover", + "solana-serde-varint", + "solana-serialize-utils", + "solana-sha256-hasher", + "solana-short-vec", + "solana-slot-hashes", + "solana-slot-history", + "solana-stable-layout", + "solana-sysvar", + "solana-sysvar-id", +] + +[[package]] +name = "solana-program-entrypoint" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84c9b0a1ff494e05f503a08b3d51150b73aa639544631e510279d6375f290997" +dependencies = [ + "solana-account-info", + "solana-define-syscall 4.0.1", + "solana-program-error", + "solana-pubkey 4.1.0", +] + +[[package]] +name = "solana-program-error" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1af32c995a7b692a915bb7414d5f8e838450cf7c70414e763d8abcae7b51f28" +dependencies = [ + "borsh", "serde", - "serde_bytes", "serde_derive", - "sha2 0.10.8", - "sha3 0.10.8", - "solana-sdk-macro", - "thiserror", - "wasm-bindgen", ] [[package]] -name = "solana-program-runtime" -version = "2.0.4" +name = "solana-program-memory" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92cb880a1b9ab10f1dfb3455f4cfc5f37f9a99e3a1c29dd01105100bda16f65f" +checksum = "4068648649653c2c50546e9a7fb761791b5ab0cda054c771bb5808d3a4b9eb52" dependencies = [ - "base64 0.22.1", - "bincode", - "eager", - "enum-iterator", - "itertools 0.12.1", - "libc", - "log", - "num-derive", - "num-traits", - "percentage", - "rand 0.8.5", - "rustc_version", - "serde", - "solana-compute-budget", - "solana-measure", - "solana-metrics", - "solana-sdk", - "solana-type-overrides", - "solana-vote", - "solana_rbpf", - "thiserror", + "solana-define-syscall 4.0.1", +] + +[[package]] +name = "solana-program-option" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e7b4ddb464f274deb4a497712664c3b612e3f5f82471d4e47710fc4ab1c3095" + +[[package]] +name = "solana-program-pack" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c169359de21f6034a63ebf96d6b380980307df17a8d371344ff04a883ec4e9d0" +dependencies = [ + "solana-program-error", ] [[package]] -name = "solana-program-test" -version = "2.0.4" +name = "solana-program-runtime" +version = "3.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "478065d24bc2b61575172e33d4ec04c40773d5f35d553b4646db3094471a57ec" +checksum = "3a03ee54e20e5562f347121517c1692489a6a8e04f86aefd5740af5097c33820" dependencies = [ - "assert_matches", - "async-trait", "base64 0.22.1", "bincode", - "chrono-humanize", - "crossbeam-channel", + "itertools", "log", + "percentage", + "rand 0.8.5", "serde", - "solana-accounts-db", - "solana-banks-client", - "solana-banks-interface", - "solana-banks-server", - "solana-bpf-loader-program", - "solana-compute-budget", - "solana-inline-spl", - "solana-logger", - "solana-program-runtime", - "solana-runtime", - "solana-sdk", - "solana-svm", - "solana-vote-program", - "solana_rbpf", - "thiserror", - "tokio", + "solana-account", + "solana-account-info", + "solana-clock", + "solana-epoch-rewards", + "solana-epoch-schedule", + "solana-fee-structure", + "solana-hash 3.1.0", + "solana-instruction", + "solana-last-restart-slot", + "solana-loader-v3-interface", + "solana-program-entrypoint", + "solana-pubkey 3.0.0", + "solana-rent", + "solana-sbpf", + "solana-sdk-ids", + "solana-slot-hashes", + "solana-stable-layout", + "solana-stake-interface", + "solana-svm-callback", + "solana-svm-feature-set", + "solana-svm-log-collector", + "solana-svm-measure", + "solana-svm-timings", + "solana-svm-transaction", + "solana-svm-type-overrides", + "solana-system-interface 2.0.0", + "solana-sysvar", + "solana-sysvar-id", + "solana-transaction-context", + "thiserror 2.0.18", +] + +[[package]] +name = "solana-pubkey" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8909d399deb0851aa524420beeb5646b115fd253ef446e35fe4504c904da3941" +dependencies = [ + "rand 0.8.5", + "solana-address 1.1.0", +] + +[[package]] +name = "solana-pubkey" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b06bd918d60111ee1f97de817113e2040ca0cedb740099ee8d646233f6b906c" +dependencies = [ + "solana-address 2.2.0", ] [[package]] name = "solana-pubsub-client" -version = "2.0.4" +version = "3.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9ce8e00084db74a62ec74dde7a5105f4997562f179c2cd53e829ee1bf9e0f72" +checksum = "1305d955b8da57ec22b0410630df61770fbae6b8e93aa91bb0fb76f01bc56f8a" dependencies = [ "crossbeam-channel", "futures-util", + "http 0.2.12", "log", - "reqwest", "semver", "serde", - "serde_derive", "serde_json", - "solana-account-decoder", - "solana-rpc-client-api", - "solana-sdk", - "thiserror", + "solana-account-decoder-client-types", + "solana-clock", + "solana-pubkey 3.0.0", + "solana-rpc-client-types", + "solana-signature", + "thiserror 2.0.18", "tokio", "tokio-stream", - "tokio-tungstenite 0.20.1", - "tungstenite 0.20.1", + "tokio-tungstenite", + "tungstenite", "url", ] [[package]] name = "solana-quic-client" -version = "2.0.4" +version = "3.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eaa82c4053b3dec1173f2406d4d143f3fb02fae6cf0bd16d48a91f860c88e29" +checksum = "e472c50da5a07aec4253857a507edfcdd3c0a03d0012f213776ccf18de0aafe0" dependencies = [ - "async-mutex", + "async-lock", "async-trait", "futures", - "itertools 0.12.1", - "lazy_static", + "itertools", "log", "quinn", "quinn-proto", "rustls", "solana-connection-cache", + "solana-keypair", "solana-measure", "solana-metrics", "solana-net-utils", + "solana-pubkey 3.0.0", + "solana-quic-definitions", "solana-rpc-client-api", - "solana-sdk", + "solana-signer", "solana-streamer", - "thiserror", + "solana-tls-utils", + "solana-transaction-error", + "thiserror 2.0.18", "tokio", ] +[[package]] +name = "solana-quic-definitions" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15319accf7d3afd845817aeffa6edd8cc185f135cefbc6b985df29cfd8c09609" +dependencies = [ + "solana-keypair", +] + [[package]] name = "solana-rayon-threadlimit" -version = "2.0.4" +version = "3.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd77a28ebc9c99c59f6ef5825ddcd379a2ad8e4177cd55f6906f77bcb3fade34" +checksum = "dbd391cd6ef3d8a3da4a6981a38050ac1449d8472bcbd394fbe1e35fc039424c" dependencies = [ - "lazy_static", + "log", "num_cpus", ] [[package]] name = "solana-remote-wallet" -version = "2.0.4" +version = "3.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1af8714a35122d9d7e5f2824e4131b3986bc49f5395a9f0bf053cb41fcad9a65" +checksum = "0f9cd2c9bd26e6f1faaa45a5d24403f85816651c31e5eb2e06a1749e129fd4e8" dependencies = [ - "console", + "console 0.16.2", "dialoguer", "log", "num-derive", @@ -4440,273 +4445,427 @@ dependencies = [ "parking_lot", "qstring", "semver", - "solana-sdk", - "thiserror", + "solana-derivation-path", + "solana-offchain-message", + "solana-pubkey 3.0.0", + "solana-signature", + "solana-signer", + "thiserror 2.0.18", "uriparse", ] +[[package]] +name = "solana-rent" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e860d5499a705369778647e97d760f7670adfb6fc8419dd3d568deccd46d5487" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-sysvar-id", +] + +[[package]] +name = "solana-reward-info" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82be7946105c2ee6be9f9ee7bd18a068b558389221d29efa92b906476102bfcc" +dependencies = [ + "serde", + "serde_derive", +] + [[package]] name = "solana-rpc-client" -version = "2.0.4" +version = "3.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08d3cd24e014882c7cf171916d5031ca3523186a5b7d1fc4d2443d139669625" +checksum = "7476104ef972be862a9c4989bb0d5798971a022a23becbd874f854733500d0a6" dependencies = [ "async-trait", "base64 0.22.1", "bincode", "bs58", + "futures", "indicatif", "log", "reqwest", "reqwest-middleware", "semver", "serde", - "serde_derive", "serde_json", + "solana-account", "solana-account-decoder", + "solana-account-decoder-client-types", + "solana-clock", + "solana-commitment-config", + "solana-epoch-info", + "solana-epoch-schedule", + "solana-feature-gate-interface", + "solana-hash 3.1.0", + "solana-instruction", + "solana-message", + "solana-pubkey 3.0.0", "solana-rpc-client-api", - "solana-sdk", - "solana-transaction-status", + "solana-signature", + "solana-transaction", + "solana-transaction-error", + "solana-transaction-status-client-types", "solana-version", - "solana-vote-program", + "solana-vote-interface", "tokio", ] [[package]] name = "solana-rpc-client-api" -version = "2.0.4" +version = "3.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "feb2ab42b151536221378f1cb8530b7c9eac796c89c9e7e8e61a01119ab12559" +checksum = "f139578f2184aa2299d36dc2da71233d695fbbe7925fed5649bf614f96783383" dependencies = [ "anyhow", - "base64 0.22.1", - "bs58", "jsonrpc-core", "reqwest", "reqwest-middleware", - "semver", "serde", - "serde_derive", "serde_json", - "solana-account-decoder", - "solana-inline-spl", - "solana-sdk", - "solana-transaction-status", - "solana-version", - "thiserror", + "solana-account-decoder-client-types", + "solana-clock", + "solana-rpc-client-types", + "solana-signer", + "solana-transaction-error", + "solana-transaction-status-client-types", + "thiserror 2.0.18", ] [[package]] name = "solana-rpc-client-nonce-utils" -version = "2.0.4" +version = "3.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5071cc8135b5a8e33c00ed953d4654a227988bd63ad2802cca88a21e7624c66f" +checksum = "28bd892ee8c80db85bf78594dde4dd2537ba11d419bf30676e7ab948da290675" dependencies = [ - "clap 2.34.0", - "solana-clap-utils", + "solana-account", + "solana-commitment-config", + "solana-hash 3.1.0", + "solana-message", + "solana-nonce", + "solana-pubkey 3.0.0", "solana-rpc-client", - "solana-sdk", - "thiserror", + "solana-sdk-ids", + "thiserror 2.0.18", ] [[package]] -name = "solana-runtime" -version = "2.0.4" +name = "solana-rpc-client-types" +version = "3.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfffd318ab3f0346442743ee554896fd31f2ded7d660ed614a23d904d2a9a99c" +checksum = "104f40726fc48ad80b6b52ba7f3300a6ea2a87307cd5560afe943027d95e2b56" dependencies = [ - "aquamarine 0.3.3", - "arrayref", "base64 0.22.1", - "bincode", - "blake3", - "bv", - "bytemuck", + "bs58", + "semver", + "serde", + "serde_json", + "solana-account", + "solana-account-decoder-client-types", + "solana-address 1.1.0", + "solana-clock", + "solana-commitment-config", + "solana-fee-calculator", + "solana-inflation", + "solana-reward-info", + "solana-transaction", + "solana-transaction-error", + "solana-transaction-status-client-types", + "solana-version", + "spl-generic-token", + "thiserror 2.0.18", +] + +[[package]] +name = "solana-sanitize" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf09694a0fc14e5ffb18f9b7b7c0f15ecb6eac5b5610bf76a1853459d19daf9" + +[[package]] +name = "solana-sbpf" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15b079e08471a9dbfe1e48b2c7439c85aa2a055cbd54eddd8bd257b0a7dbb29" +dependencies = [ "byteorder", - "bzip2", - "crossbeam-channel", - "dashmap", - "dir-diff", - "flate2", - "fnv", - "im", - "index_list", - "itertools 0.12.1", - "lazy_static", + "combine 3.8.1", + "hash32", "libc", "log", - "lz4", - "memmap2", - "mockall", - "modular-bitfield", - "num-derive", - "num-traits", - "num_cpus", - "num_enum", - "percentage", - "qualifier_attr", "rand 0.8.5", - "rayon", - "regex", - "rustc_version", - "serde", - "serde_derive", - "serde_json", - "solana-accounts-db", - "solana-address-lookup-table-program", - "solana-bpf-loader-program", - "solana-bucket-map", - "solana-compute-budget", - "solana-compute-budget-program", - "solana-config-program", - "solana-cost-model", - "solana-inline-spl", - "solana-loader-v4-program", - "solana-measure", - "solana-metrics", - "solana-perf", - "solana-program-runtime", - "solana-rayon-threadlimit", - "solana-sdk", - "solana-stake-program", - "solana-svm", - "solana-system-program", - "solana-transaction-status", - "solana-version", - "solana-vote", - "solana-vote-program", - "solana-zk-elgamal-proof-program", - "solana-zk-sdk", - "solana-zk-token-proof-program", - "solana-zk-token-sdk", - "static_assertions", - "strum", - "strum_macros", - "symlink", - "tar", - "tempfile", - "thiserror", - "zstd", + "rustc-demangle", + "thiserror 2.0.18", + "winapi", ] [[package]] name = "solana-sdk" -version = "2.0.4" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37f55b64bb1a3f4b4d83a880933ff3d08a6d5857e5db481fec183df45ab58dad" +checksum = "3f03df7969f5e723ad31b6c9eadccc209037ac4caa34d8dc259316b05c11e82b" dependencies = [ "bincode", - "bitflags 2.6.0", - "borsh 1.5.1", "bs58", - "bytemuck", - "bytemuck_derive", - "byteorder", - "chrono", - "derivation-path", - "digest 0.10.7", - "ed25519-dalek", - "ed25519-dalek-bip32", - "generic-array", - "getrandom 0.1.16", - "hmac 0.12.1", - "itertools 0.12.1", - "js-sys", - "lazy_static", - "libsecp256k1", - "log", - "memmap2", - "num_enum", - "pbkdf2 0.11.0", - "qstring", - "rand 0.7.3", - "rand 0.8.5", - "rustc_version", - "rustversion", "serde", - "serde_bytes", - "serde_derive", - "serde_json", - "serde_with", - "sha2 0.10.8", - "sha3 0.10.8", - "siphasher", + "solana-account", + "solana-epoch-info", + "solana-epoch-rewards-hasher", + "solana-fee-structure", + "solana-inflation", + "solana-keypair", + "solana-message", + "solana-offchain-message", + "solana-presigner", "solana-program", + "solana-program-memory", + "solana-pubkey 3.0.0", + "solana-sanitize", + "solana-sdk-ids", "solana-sdk-macro", - "thiserror", - "uriparse", - "wasm-bindgen", + "solana-seed-derivable", + "solana-seed-phrase", + "solana-serde", + "solana-serde-varint", + "solana-short-vec", + "solana-shred-version", + "solana-signature", + "solana-signer", + "solana-time-utils", + "solana-transaction", + "solana-transaction-error", + "thiserror 2.0.18", +] + +[[package]] +name = "solana-sdk-ids" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "def234c1956ff616d46c9dd953f251fa7096ddbaa6d52b165218de97882b7280" +dependencies = [ + "solana-address 2.2.0", ] [[package]] name = "solana-sdk-macro" -version = "2.0.4" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6073cfb240aa571f11511ea3add3a699a44e7e80c696b34b30a6fc126827c9f" +checksum = "d6430000e97083460b71d9fbadc52a2ab2f88f53b3a4c5e58c5ae3640a0e8c00" dependencies = [ "bs58", "proc-macro2", "quote", - "rustversion", - "syn 2.0.72", + "syn 2.0.115", +] + +[[package]] +name = "solana-secp256k1-recover" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9de18cfdab99eeb940fbedd8c981fa130c0d76252da75d05446f22fae8b51932" +dependencies = [ + "k256", + "solana-define-syscall 4.0.1", + "thiserror 2.0.18", ] [[package]] name = "solana-security-txt" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "468aa43b7edb1f9b7b7b686d5c3aeb6630dc1708e86e31343499dd5c4d775183" +checksum = "156bb61a96c605fa124e052d630dba2f6fb57e08c7d15b757e1e958b3ed7b3fe" +dependencies = [ + "hashbrown 0.15.2", +] [[package]] -name = "solana-send-transaction-service" -version = "2.0.4" +name = "solana-seed-derivable" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a0b3ead2e93ada40867d11bace4cbff184c63f988dada49c1b86389741b6b31" +checksum = "ff7bdb72758e3bec33ed0e2658a920f1f35dfb9ed576b951d20d63cb61ecd95c" dependencies = [ - "crossbeam-channel", - "log", - "solana-client", - "solana-connection-cache", - "solana-measure", - "solana-metrics", - "solana-runtime", - "solana-sdk", - "solana-tpu-client", + "solana-derivation-path", +] + +[[package]] +name = "solana-seed-phrase" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc905b200a95f2ea9146e43f2a7181e3aeb55de6bc12afb36462d00a3c7310de" +dependencies = [ + "hmac", + "pbkdf2 0.11.0", + "sha2", +] + +[[package]] +name = "solana-serde" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "709a93cab694c70f40b279d497639788fc2ccbcf9b4aa32273d4b361322c02dd" +dependencies = [ + "serde", +] + +[[package]] +name = "solana-serde-varint" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e5174c57d5ff3c1995f274d17156964664566e2cde18a07bba1586d35a70d3b" +dependencies = [ + "serde", +] + +[[package]] +name = "solana-serialize-utils" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e41dd8feea239516c623a02f0a81c2367f4b604d7965237fed0751aeec33ed" +dependencies = [ + "solana-instruction-error", + "solana-pubkey 3.0.0", + "solana-sanitize", +] + +[[package]] +name = "solana-sha256-hasher" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db7dc3011ea4c0334aaaa7e7128cb390ecf546b28d412e9bf2064680f57f588f" +dependencies = [ + "sha2", + "solana-define-syscall 4.0.1", + "solana-hash 4.2.0", +] + +[[package]] +name = "solana-short-vec" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3bd991c2cc415291c86bb0b6b4d53e93d13bb40344e4c5a2884e0e4f5fa93f" +dependencies = [ + "serde_core", +] + +[[package]] +name = "solana-shred-version" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94953e22ca28fe4541a3447d6baeaf519cc4ddc063253bfa673b721f34c136bb" +dependencies = [ + "solana-hard-forks", + "solana-hash 3.1.0", + "solana-sha256-hasher", +] + +[[package]] +name = "solana-signature" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "132a93134f1262aa832f1849b83bec6c9945669b866da18661a427943b9e801e" +dependencies = [ + "ed25519-dalek", + "five8", + "rand 0.9.2", + "serde", + "serde-big-array", + "serde_derive", + "solana-sanitize", + "wincode", +] + +[[package]] +name = "solana-signer" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bfea97951fee8bae0d6038f39a5efcb6230ecdfe33425ac75196d1a1e3e3235" +dependencies = [ + "solana-pubkey 3.0.0", + "solana-signature", + "solana-transaction-error", +] + +[[package]] +name = "solana-slot-hashes" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80a293f952293281443c04f4d96afd9d547721923d596e92b4377ed2360f1746" +dependencies = [ + "serde", + "serde_derive", + "solana-hash 3.1.0", + "solana-sdk-ids", + "solana-sysvar-id", +] + +[[package]] +name = "solana-slot-history" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f914f6b108f5bba14a280b458d023e3621c9973f27f015a4d755b50e88d89e97" +dependencies = [ + "bv", + "serde", + "serde_derive", + "solana-sdk-ids", + "solana-sysvar-id", +] + +[[package]] +name = "solana-stable-layout" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1da74507795b6e8fb60b7c7306c0c36e2c315805d16eaaf479452661234685ac" +dependencies = [ + "solana-instruction", + "solana-pubkey 3.0.0", ] [[package]] -name = "solana-stake-program" -version = "2.0.4" +name = "solana-stake-interface" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d78dc348f8df8f89731d0d2ccd2e9929a8e555903b8b0d97a8832fd46febee94" +checksum = "b9bc26191b533f9a6e5a14cca05174119819ced680a80febff2f5051a713f0db" dependencies = [ - "bincode", - "log", - "rustc_version", - "solana-config-program", - "solana-program-runtime", - "solana-sdk", - "solana-type-overrides", - "solana-vote-program", + "num-traits", + "serde", + "serde_derive", + "solana-clock", + "solana-cpi", + "solana-instruction", + "solana-program-error", + "solana-pubkey 3.0.0", + "solana-system-interface 2.0.0", + "solana-sysvar", + "solana-sysvar-id", ] [[package]] name = "solana-streamer" -version = "2.0.4" +version = "3.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de93cce4fb6b6b925a7f41c5880391189cfa82a1422b05b75d094a337739c844" +checksum = "f71881ba229a4dbdc1790ad6d367f40dd42b4eea0e8ef1076d867c27424d5d4c" dependencies = [ - "async-channel", + "arc-swap", "bytes", "crossbeam-channel", "dashmap", + "futures", "futures-util", + "governor", "histogram", - "indexmap 2.3.0", - "itertools 0.12.1", + "indexmap", + "itertools", "libc", "log", "nix", + "num_cpus", "pem", "percentage", "quinn", @@ -4714,232 +4873,448 @@ dependencies = [ "rand 0.8.5", "rustls", "smallvec", + "socket2", + "solana-keypair", "solana-measure", "solana-metrics", + "solana-net-utils", + "solana-packet", "solana-perf", - "solana-sdk", + "solana-pubkey 3.0.0", + "solana-quic-definitions", + "solana-signature", + "solana-signer", + "solana-time-utils", + "solana-tls-utils", + "solana-transaction-error", "solana-transaction-metrics-tracker", - "thiserror", + "thiserror 2.0.18", "tokio", + "tokio-util", "x509-parser", ] [[package]] -name = "solana-svm" -version = "2.0.4" +name = "solana-svm-callback" +version = "3.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c216afeef20cf86fd3d2ae812bebcdc23ee0e3d45fb4b3b28ad168cb56778ed" +dependencies = [ + "solana-account", + "solana-clock", + "solana-precompile-error", + "solana-pubkey 3.0.0", +] + +[[package]] +name = "solana-svm-feature-set" +version = "3.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "641cddc667abba4cf3474d850a073c0a2b439ff0014c445cd09eaf5d79d70bab" + +[[package]] +name = "solana-svm-log-collector" +version = "3.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9f7368938f2fe8b585d850977a6085ae5e7b5d8fb52c0fa58a2c47c84bb2c0a" +checksum = "bbe6ce42b1620fd713e12cd52d62a7d4d370414d67ed9bfc5faa444fa54bb6f2" dependencies = [ - "itertools 0.12.1", "log", - "percentage", - "prost-build", - "qualifier_attr", - "rustc_version", +] + +[[package]] +name = "solana-svm-measure" +version = "3.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea1d8035045fe47df97ee2a4695b09236161f82f1b4b6c2a49a5cb6a7c94fed6" + +[[package]] +name = "solana-svm-timings" +version = "3.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9b6407ecacc9b1ca88bdb34f6afb10ab0e4c65f3f1b82bce637c3056deb456d" +dependencies = [ + "eager", + "enum-iterator", + "solana-pubkey 3.0.0", +] + +[[package]] +name = "solana-svm-transaction" +version = "3.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9ca13fa9a99ad8474c3867d56d81effcf5582bb6356ab0a9ed2fc373a3e4af7" +dependencies = [ + "solana-hash 3.1.0", + "solana-message", + "solana-pubkey 3.0.0", + "solana-sdk-ids", + "solana-signature", + "solana-transaction", +] + +[[package]] +name = "solana-svm-type-overrides" +version = "3.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe572aba18afc347a699927720ddc8671da94663a6453e30e872f3ac3788da22" +dependencies = [ + "rand 0.8.5", +] + +[[package]] +name = "solana-system-interface" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e1790547bfc3061f1ee68ea9d8dc6c973c02a163697b24263a8e9f2e6d4afa2" +dependencies = [ + "num-traits", "serde", "serde_derive", - "solana-bpf-loader-program", - "solana-compute-budget", - "solana-loader-v4-program", - "solana-measure", - "solana-metrics", - "solana-program-runtime", - "solana-sdk", - "solana-system-program", - "solana-type-overrides", - "solana-vote", + "solana-instruction", + "solana-msg", + "solana-program-error", + "solana-pubkey 3.0.0", ] [[package]] -name = "solana-system-program" -version = "2.0.4" +name = "solana-system-interface" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85a6bbd155b649672cc440b1236cfba455d818f6efa6b9316b07f710f8b4e872" +checksum = "14591d6508042ebefb110305d3ba761615927146a26917ade45dc332d8e1ecde" dependencies = [ - "bincode", - "log", + "num-traits", "serde", "serde_derive", - "solana-program-runtime", - "solana-sdk", - "solana-type-overrides", + "solana-address 2.2.0", + "solana-instruction", + "solana-msg", + "solana-program-error", ] [[package]] -name = "solana-thin-client" -version = "2.0.4" +name = "solana-sysvar" +version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63cad10e52c96b2b052841ea6d755742c64f58c07690cb59502bfb6f450d76de" +checksum = "6690d3dd88f15c21edff68eb391ef8800df7a1f5cec84ee3e8d1abf05affdf74" dependencies = [ + "base64 0.22.1", "bincode", - "log", - "rayon", - "solana-connection-cache", - "solana-rpc-client", - "solana-rpc-client-api", - "solana-sdk", + "bytemuck", + "bytemuck_derive", + "lazy_static", + "serde", + "serde_derive", + "solana-account-info", + "solana-clock", + "solana-define-syscall 4.0.1", + "solana-epoch-rewards", + "solana-epoch-schedule", + "solana-fee-calculator", + "solana-hash 4.2.0", + "solana-instruction", + "solana-last-restart-slot", + "solana-program-entrypoint", + "solana-program-error", + "solana-program-memory", + "solana-pubkey 4.1.0", + "solana-rent", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-slot-hashes", + "solana-slot-history", + "solana-sysvar-id", +] + +[[package]] +name = "solana-sysvar-id" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17358d1e9a13e5b9c2264d301102126cf11a47fd394cdf3dec174fe7bc96e1de" +dependencies = [ + "solana-address 2.2.0", + "solana-sdk-ids", +] + +[[package]] +name = "solana-time-utils" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ced92c60aa76ec4780a9d93f3bd64dfa916e1b998eacc6f1c110f3f444f02c9" + +[[package]] +name = "solana-tls-utils" +version = "3.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3460fa9475f912185e11e89d496ef08aae9db26d0c95a622d71b59e17dd0af8f" +dependencies = [ + "rustls", + "solana-keypair", + "solana-pubkey 3.0.0", + "solana-signer", + "x509-parser", ] [[package]] name = "solana-tpu-client" -version = "2.0.4" +version = "3.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ed153ba69d661b9ab53ce1ab6fc554218ddab3aa622004eb0991bfa5b20f12a" +checksum = "b82d41c68b8ff70ef4a952aa40cbe1a4ffe41a4ff7d329f925568f096e6b3f8b" dependencies = [ "async-trait", "bincode", "futures-util", - "indexmap 2.3.0", + "indexmap", "indicatif", "log", "rayon", + "solana-client-traits", + "solana-clock", + "solana-commitment-config", "solana-connection-cache", + "solana-epoch-schedule", "solana-measure", - "solana-metrics", + "solana-message", + "solana-net-utils", + "solana-pubkey 3.0.0", "solana-pubsub-client", + "solana-quic-definitions", "solana-rpc-client", "solana-rpc-client-api", - "solana-sdk", - "thiserror", + "solana-signature", + "solana-signer", + "solana-transaction", + "solana-transaction-error", + "thiserror 2.0.18", "tokio", ] +[[package]] +name = "solana-transaction" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96697cff5075a028265324255efed226099f6d761ca67342b230d09f72cc48d2" +dependencies = [ + "bincode", + "serde", + "serde_derive", + "solana-address 2.2.0", + "solana-hash 4.2.0", + "solana-instruction", + "solana-instruction-error", + "solana-message", + "solana-sanitize", + "solana-sdk-ids", + "solana-short-vec", + "solana-signature", + "solana-signer", + "solana-transaction-error", +] + +[[package]] +name = "solana-transaction-context" +version = "3.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f55a9c2e2af954fae402f08e210c7f01d6a8517ad358f8f0db11ed7de89b02d4" +dependencies = [ + "bincode", + "serde", + "solana-account", + "solana-instruction", + "solana-instructions-sysvar", + "solana-pubkey 3.0.0", + "solana-rent", + "solana-sbpf", + "solana-sdk-ids", +] + +[[package]] +name = "solana-transaction-error" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4222065402340d7e6aec9dc3e54d22992ddcf923d91edcd815443c2bfca3144a" +dependencies = [ + "serde", + "serde_derive", + "solana-instruction-error", + "solana-sanitize", +] + [[package]] name = "solana-transaction-metrics-tracker" -version = "2.0.4" +version = "3.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a72e38ccdb38b862c4b3081a0a8ddca18a8321a358630d1497018221da00cde" +checksum = "de0c780ebbf9ab558a9b9eff409d166c50c81dcbe012b8a488f3f12c042c39c4" dependencies = [ - "Inflector", "base64 0.22.1", "bincode", - "lazy_static", "log", "rand 0.8.5", + "solana-packet", "solana-perf", - "solana-sdk", + "solana-short-vec", + "solana-signature", ] [[package]] name = "solana-transaction-status" -version = "2.0.4" +version = "3.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbb97183f3033bfad0e31e9d078add9272f3771a4641b1eb2e384955e98f4c5a" +checksum = "afe59d2c9a9ff1bb05150ebc5b1a945642760977da3715b9e1c403f0a29d3805" dependencies = [ "Inflector", + "agave-reserved-account-keys", "base64 0.22.1", "bincode", - "borsh 1.5.1", + "borsh", "bs58", - "lazy_static", "log", "serde", - "serde_derive", "serde_json", "solana-account-decoder", - "solana-sdk", - "spl-associated-token-account", - "spl-memo", - "spl-token", - "spl-token-2022", + "solana-address-lookup-table-interface", + "solana-clock", + "solana-hash 3.1.0", + "solana-instruction", + "solana-loader-v2-interface", + "solana-loader-v3-interface", + "solana-message", + "solana-program-option", + "solana-pubkey 3.0.0", + "solana-reward-info", + "solana-sdk-ids", + "solana-signature", + "solana-stake-interface", + "solana-system-interface 2.0.0", + "solana-transaction", + "solana-transaction-error", + "solana-transaction-status-client-types", + "solana-vote-interface", + "spl-associated-token-account-interface", + "spl-memo-interface", + "spl-token-2022-interface", "spl-token-group-interface", + "spl-token-interface", "spl-token-metadata-interface", - "thiserror", + "thiserror 2.0.18", ] [[package]] -name = "solana-type-overrides" -version = "2.0.4" +name = "solana-transaction-status-client-types" +version = "3.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc7267be5ef0ca824929e2632b82c07fde7056ae5d0481a87fb7223978f3c4eb" +checksum = "1341840c0ba1028b918b03c9ba9900019f739ee23946baf76574ec0a5dab8231" dependencies = [ - "lazy_static", - "rand 0.8.5", + "base64 0.22.1", + "bincode", + "bs58", + "serde", + "serde_json", + "solana-account-decoder-client-types", + "solana-commitment-config", + "solana-instruction", + "solana-message", + "solana-pubkey 3.0.0", + "solana-reward-info", + "solana-signature", + "solana-transaction", + "solana-transaction-context", + "solana-transaction-error", + "thiserror 2.0.18", ] [[package]] name = "solana-udp-client" -version = "2.0.4" +version = "3.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd0e09f75263f5642fbfcf25f43b4add81831deb8891e3773b004bb852aae5ca" +checksum = "02efe0168dc03038aadcf3915defa3e8440e705898d9c1cdac99cb70ef20c275" dependencies = [ "async-trait", "solana-connection-cache", + "solana-keypair", "solana-net-utils", - "solana-sdk", "solana-streamer", - "thiserror", + "solana-transaction-error", + "thiserror 2.0.18", "tokio", ] [[package]] name = "solana-version" -version = "2.0.4" +version = "3.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4abd65eb3a9b5c1d523df8d8dc2ecf88fc63bb638cedc6c918ce193228478be9" +checksum = "f2642d930b9ef476bfb5d64bac62d35b37dfb415cdf7b0a642c3c0ca537f1a7b" dependencies = [ - "log", - "rustc_version", + "agave-feature-set", + "rand 0.8.5", "semver", "serde", - "serde_derive", - "solana-sdk", + "solana-sanitize", + "solana-serde-varint", ] [[package]] -name = "solana-vote" -version = "2.0.4" +name = "solana-vote-interface" +version = "4.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dc534f8cd9fe254ae1729f762bde773c4c3f6cc364b87798b2e46d7dfbe6763" +checksum = "db6e123e16bfdd7a81d71b4c4699e0b29580b619f4cd2ef5b6aae1eb85e8979f" dependencies = [ - "itertools 0.12.1", - "log", - "rustc_version", + "bincode", + "cfg_eval", + "num-derive", + "num-traits", "serde", "serde_derive", - "solana-sdk", - "thiserror", + "serde_with", + "solana-clock", + "solana-hash 3.1.0", + "solana-instruction", + "solana-instruction-error", + "solana-pubkey 3.0.0", + "solana-rent", + "solana-sdk-ids", + "solana-serde-varint", + "solana-serialize-utils", + "solana-short-vec", + "solana-system-interface 2.0.0", ] [[package]] name = "solana-vote-program" -version = "2.0.4" +version = "3.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046901822aacc1b3587cfcd5eeb3b9cf192c75215b0a3db3daa5f5ecff581d1f" +checksum = "de77cc3a9dc9c1247d779db24a5c3bb5cf533855ccfa0ddb12c0c773c26acf4e" dependencies = [ + "agave-feature-set", "bincode", "log", "num-derive", "num-traits", - "rustc_version", "serde", - "serde_derive", - "solana-metrics", - "solana-program", - "solana-program-runtime", - "solana-sdk", - "thiserror", -] - -[[package]] -name = "solana-zk-elgamal-proof-program" -version = "2.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d399e3b6ea6f8cc7b29c9a796d3f9e165157197fc1f55d4b08f81ce4647c96fa" -dependencies = [ - "bytemuck", - "num-derive", - "num-traits", + "solana-account", + "solana-bincode", + "solana-clock", + "solana-epoch-schedule", + "solana-hash 3.1.0", + "solana-instruction", + "solana-keypair", + "solana-packet", "solana-program-runtime", - "solana-sdk", - "solana-zk-sdk", + "solana-pubkey 3.0.0", + "solana-rent", + "solana-sdk-ids", + "solana-signer", + "solana-slot-hashes", + "solana-transaction", + "solana-transaction-context", + "solana-vote-interface", + "thiserror 2.0.18", ] [[package]] name = "solana-zk-sdk" -version = "2.0.4" +version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b830d0714ce2988da09c5dacc394dee2b5c89694dde986f951289e38d883576" +checksum = "9602bcb1f7af15caef92b91132ec2347e1c51a72ecdbefdaefa3eac4b8711475" dependencies = [ "aes-gcm-siv", "base64 0.22.1", @@ -4947,338 +5322,560 @@ dependencies = [ "bytemuck", "bytemuck_derive", "curve25519-dalek", - "itertools 0.12.1", - "lazy_static", + "getrandom 0.2.17", + "itertools", + "js-sys", "merlin", "num-derive", "num-traits", - "rand 0.7.3", + "rand 0.8.5", "serde", "serde_derive", "serde_json", - "sha3 0.9.1", - "solana-program", - "solana-sdk", + "sha3", + "solana-derivation-path", + "solana-instruction", + "solana-pubkey 3.0.0", + "solana-sdk-ids", + "solana-seed-derivable", + "solana-seed-phrase", + "solana-signature", + "solana-signer", "subtle", - "thiserror", + "thiserror 2.0.18", + "wasm-bindgen", "zeroize", ] [[package]] -name = "solana-zk-token-proof-program" -version = "2.0.4" +name = "spinning_top" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61259b7c27b6a73f5f85f15e93b8fb159cf7a7b528ce6fcf28f304d1f6a47b43" +checksum = "d96d2d1d716fb500937168cc09353ffdc7a012be8475ac7308e1bdf0e3923300" dependencies = [ - "bytemuck", - "num-derive", - "num-traits", - "solana-program-runtime", - "solana-sdk", - "solana-zk-token-sdk", + "lock_api", ] [[package]] -name = "solana-zk-token-sdk" -version = "2.0.4" +name = "spki" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4da78911f3d5a393bd6ef54f2f6301c0153b3c61e17d514e692fb9b83263422" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" dependencies = [ - "aes-gcm-siv", - "base64 0.22.1", - "bincode", - "bytemuck", - "bytemuck_derive", - "byteorder", - "curve25519-dalek", - "itertools 0.12.1", - "lazy_static", - "merlin", - "num-derive", - "num-traits", - "rand 0.7.3", - "serde", - "serde_derive", - "serde_json", - "sha3 0.9.1", - "solana-curve25519", - "solana-program", - "solana-sdk", - "subtle", - "thiserror", - "zeroize", + "base64ct", + "der", ] [[package]] -name = "solana_rbpf" -version = "0.8.1" +name = "spl-associated-token-account" +version = "8.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06beab07f4104d6ad70d47baa67ad1bcd501a2345a983e20c389bade7c72305e" +checksum = "0242277e290c023de8826f504abcf9206b3cd4e18d9ace4ec59a698b2828e88b" dependencies = [ - "byteorder", - "combine", - "goblin", - "hash32", - "libc", - "log", - "rand 0.8.5", - "rustc-demangle", - "scroll", - "thiserror", - "winapi", + "borsh", + "num-derive", + "num-traits", + "solana-account-info", + "solana-cpi", + "solana-instruction", + "solana-msg", + "solana-program-entrypoint", + "solana-program-error", + "solana-pubkey 3.0.0", + "solana-rent", + "solana-sdk-ids", + "solana-system-interface 2.0.0", + "solana-sysvar", + "spl-associated-token-account-interface", + "spl-token-2022-interface", + "spl-token-interface", + "thiserror 2.0.18", +] + +[[package]] +name = "spl-associated-token-account-interface" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6433917b60441d68d99a17e121d9db0ea15a9a69c0e5afa34649cf5ba12612f" +dependencies = [ + "borsh", + "solana-instruction", + "solana-pubkey 3.0.0", ] [[package]] -name = "spin" -version = "0.5.2" +name = "spl-discriminator" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +checksum = "d48cc11459e265d5b501534144266620289720b4c44522a47bc6b63cd295d2f3" +dependencies = [ + "bytemuck", + "solana-program-error", + "solana-sha256-hasher", + "spl-discriminator-derive", +] [[package]] -name = "spin" -version = "0.9.8" +name = "spl-discriminator-derive" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +checksum = "d9e8418ea6269dcfb01c712f0444d2c75542c04448b480e87de59d2865edc750" +dependencies = [ + "quote", + "spl-discriminator-syn", + "syn 2.0.115", +] [[package]] -name = "spl-associated-token-account" -version = "4.0.0" +name = "spl-discriminator-syn" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68034596cf4804880d265f834af1ff2f821ad5293e41fa0f8f59086c181fc38e" +checksum = "5d1dbc82ab91422345b6df40a79e2b78c7bce1ebb366da323572dd60b7076b67" dependencies = [ - "assert_matches", - "borsh 1.5.1", - "num-derive", - "num-traits", - "solana-program", - "spl-token", - "spl-token-2022", - "thiserror", + "proc-macro2", + "quote", + "sha2", + "syn 2.0.115", + "thiserror 1.0.69", ] [[package]] -name = "spl-discriminator" -version = "0.3.0" +name = "spl-elgamal-registry" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a38ea8b6dedb7065887f12d62ed62c1743aa70749e8558f963609793f6fb12bc" +checksum = "2bd22edf24c47c4610b160f49c12fe33b19aec2a0968e3c9cd412fa2a94ae2bb" dependencies = [ "bytemuck", - "solana-program", - "spl-discriminator-derive", + "solana-account-info", + "solana-cpi", + "solana-instruction", + "solana-msg", + "solana-program-entrypoint", + "solana-program-error", + "solana-pubkey 3.0.0", + "solana-rent", + "solana-sdk-ids", + "solana-security-txt", + "solana-system-interface 2.0.0", + "solana-sysvar", + "solana-zk-sdk", + "spl-elgamal-registry-interface", + "spl-pod", + "spl-token-confidential-transfer-proof-extraction", ] [[package]] -name = "spl-discriminator-derive" -version = "0.2.0" +name = "spl-elgamal-registry-interface" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9e8418ea6269dcfb01c712f0444d2c75542c04448b480e87de59d2865edc750" +checksum = "065f54100d118d24036283e03120b2f60cb5b7d597d3db649e13690e22d41398" dependencies = [ - "quote", - "spl-discriminator-syn", - "syn 2.0.72", + "bytemuck", + "solana-instruction", + "solana-program-error", + "solana-pubkey 3.0.0", + "solana-sdk-ids", + "solana-zk-sdk", + "spl-token-confidential-transfer-proof-extraction", ] [[package]] -name = "spl-discriminator-syn" -version = "0.2.0" +name = "spl-generic-token" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c1f05593b7ca9eac7caca309720f2eafb96355e037e6d373b909a80fe7b69b9" +checksum = "233df81b75ab99b42f002b5cdd6e65a7505ffa930624f7096a7580a56765e9cf" dependencies = [ - "proc-macro2", - "quote", - "sha2 0.10.8", - "syn 2.0.72", - "thiserror", + "bytemuck", + "solana-pubkey 3.0.0", ] [[package]] -name = "spl-memo" -version = "5.0.0" +name = "spl-memo-interface" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0dba2f2bb6419523405d21c301a32c9f9568354d4742552e7972af801f4bdb3" +checksum = "3d4e2aedd58f858337fa609af5ad7100d4a243fdaf6a40d6eb4c28c5f19505d3" dependencies = [ - "solana-program", + "solana-instruction", + "solana-pubkey 3.0.0", ] [[package]] name = "spl-pod" -version = "0.3.1" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c704c88fc457fa649ba3aabe195c79d885c3f26709efaddc453c8de352c90b87" +checksum = "b1233fdecd7461611d69bb87bc2e95af742df47291975d21232a0be8217da9de" dependencies = [ - "borsh 1.5.1", + "borsh", "bytemuck", "bytemuck_derive", - "solana-program", - "solana-zk-token-sdk", - "spl-program-error", + "num-derive", + "num-traits", + "num_enum", + "solana-program-error", + "solana-program-option", + "solana-pubkey 3.0.0", + "solana-zk-sdk", + "thiserror 2.0.18", ] [[package]] name = "spl-program-error" -version = "0.5.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7b28bed65356558133751cc32b48a7a5ddfc59ac4e941314630bbed1ac10532" +checksum = "9c4f6cf26cb6768110bf024bc7224326c720d711f7ad25d16f40f6cee40edb2d" dependencies = [ "num-derive", "num-traits", - "solana-program", + "num_enum", + "solana-msg", + "solana-program-error", "spl-program-error-derive", - "thiserror", + "thiserror 2.0.18", ] [[package]] name = "spl-program-error-derive" -version = "0.4.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d375dd76c517836353e093c2dbb490938ff72821ab568b545fd30ab3256b3e" +checksum = "9ec8965aa4dc6c74701cbb48b9cad5af35b9a394514934949edbb357b78f840d" dependencies = [ "proc-macro2", "quote", - "sha2 0.10.8", - "syn 2.0.72", + "sha2", + "syn 2.0.115", +] + +[[package]] +name = "spl-record" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fda0eb42ca6387770d7f0e764ecd8fa863f4529e9ff35fbf146576b5f4372587" +dependencies = [ + "bytemuck", + "num-derive", + "num-traits", + "solana-account-info", + "solana-instruction", + "solana-msg", + "solana-program-entrypoint", + "solana-program-error", + "solana-program-pack", + "solana-pubkey 3.0.0", + "solana-rent", + "solana-security-txt", + "thiserror 2.0.18", ] [[package]] name = "spl-tlv-account-resolution" -version = "0.7.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37a75a5f0fcc58126693ed78a17042e9dc53f07e357d6be91789f7d62aff61a4" +checksum = "6927f613c9d7ce20835d3cefb602137cab2518e383a047c0eaa58054a60644c8" dependencies = [ "bytemuck", - "solana-program", + "num-derive", + "num-traits", + "num_enum", + "solana-account-info", + "solana-instruction", + "solana-program-error", + "solana-pubkey 3.0.0", "spl-discriminator", "spl-pod", "spl-program-error", "spl-type-length-value", + "thiserror 2.0.18", ] [[package]] name = "spl-token" -version = "6.0.0" +version = "9.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70a0f06ac7f23dc0984931b1fe309468f14ea58e32660439c1cef19456f5d0e3" +checksum = "878b0183d51fcd8a53e1604f4c13321894cf53227e6773c529b0d03d499a8dfd" dependencies = [ "arrayref", "bytemuck", "num-derive", "num-traits", "num_enum", - "solana-program", - "thiserror", + "solana-account-info", + "solana-cpi", + "solana-instruction", + "solana-msg", + "solana-program-entrypoint", + "solana-program-error", + "solana-program-memory", + "solana-program-option", + "solana-program-pack", + "solana-pubkey 3.0.0", + "solana-rent", + "solana-sdk-ids", + "solana-sysvar", + "spl-token-interface", + "thiserror 2.0.18", ] [[package]] name = "spl-token-2022" -version = "4.0.0" +version = "10.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9c10f3483e48679619c76598d4e4aebb955bc49b0a5cc63323afbf44135c9bf" +checksum = "552427d9117528d037daa0e70416d51322c8a33241317210f230304d852be61e" dependencies = [ "arrayref", "bytemuck", "num-derive", "num-traits", "num_enum", - "solana-program", + "solana-account-info", + "solana-clock", + "solana-cpi", + "solana-instruction", + "solana-msg", + "solana-program-entrypoint", + "solana-program-error", + "solana-program-memory", + "solana-program-option", + "solana-program-pack", + "solana-pubkey 3.0.0", + "solana-rent", + "solana-sdk-ids", "solana-security-txt", - "solana-zk-token-sdk", - "spl-memo", + "solana-system-interface 2.0.0", + "solana-sysvar", + "solana-zk-sdk", + "spl-elgamal-registry-interface", + "spl-memo-interface", "spl-pod", - "spl-token", + "spl-token-2022-interface", + "spl-token-confidential-transfer-ciphertext-arithmetic", + "spl-token-confidential-transfer-proof-extraction", + "spl-token-confidential-transfer-proof-generation", "spl-token-group-interface", "spl-token-metadata-interface", "spl-transfer-hook-interface", + "thiserror 2.0.18", +] + +[[package]] +name = "spl-token-2022-interface" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fcd81188211f4b3c8a5eba7fd534c7142f9dd026123b3472492782cc72f4dc6" +dependencies = [ + "arrayref", + "bytemuck", + "num-derive", + "num-traits", + "num_enum", + "solana-account-info", + "solana-instruction", + "solana-program-error", + "solana-program-option", + "solana-program-pack", + "solana-pubkey 3.0.0", + "solana-sdk-ids", + "solana-zk-sdk", + "spl-pod", + "spl-token-confidential-transfer-proof-extraction", + "spl-token-confidential-transfer-proof-generation", + "spl-token-group-interface", + "spl-token-metadata-interface", "spl-type-length-value", - "thiserror", + "thiserror 2.0.18", ] [[package]] name = "spl-token-client" -version = "0.11.0" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b9f87ea372d6d98745a504b3cb5fb30dd5c1b9c714c98772452491d0188287" +checksum = "f5f87005f510593cc674a4f9f257bedbecfbb35f5aae1b66a65ef9b7dbccdeb5" dependencies = [ "async-trait", - "curve25519-dalek", + "bincode", + "bytemuck", "futures", "futures-util", - "solana-banks-interface", + "solana-account", "solana-cli-output", - "solana-program-test", + "solana-compute-budget-interface", + "solana-hash 3.1.0", + "solana-instruction", + "solana-message", + "solana-packet", + "solana-program-error", + "solana-program-pack", + "solana-pubkey 3.0.0", "solana-rpc-client", "solana-rpc-client-api", - "solana-sdk", - "spl-associated-token-account", - "spl-memo", - "spl-token", + "solana-signature", + "solana-signer", + "solana-system-interface 2.0.0", + "solana-transaction", + "spl-associated-token-account-interface", + "spl-elgamal-registry", + "spl-memo-interface", + "spl-record", "spl-token-2022", + "spl-token-2022-interface", + "spl-token-confidential-transfer-proof-extraction", + "spl-token-confidential-transfer-proof-generation", "spl-token-group-interface", + "spl-token-interface", "spl-token-metadata-interface", "spl-transfer-hook-interface", - "thiserror", + "thiserror 2.0.18", + "tokio", +] + +[[package]] +name = "spl-token-confidential-transfer-ciphertext-arithmetic" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afbeb07f737d868f145512a4bcf9f59da275b7a3483df0add3f71eb812b689fb" +dependencies = [ + "base64 0.22.1", + "bytemuck", + "solana-curve25519", + "solana-zk-sdk", +] + +[[package]] +name = "spl-token-confidential-transfer-proof-extraction" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879a9ebad0d77383d3ea71e7de50503554961ff0f4ef6cbca39ad126e6f6da3a" +dependencies = [ + "bytemuck", + "solana-account-info", + "solana-curve25519", + "solana-instruction", + "solana-instructions-sysvar", + "solana-msg", + "solana-program-error", + "solana-pubkey 3.0.0", + "solana-sdk-ids", + "solana-zk-sdk", + "spl-pod", + "thiserror 2.0.18", +] + +[[package]] +name = "spl-token-confidential-transfer-proof-generation" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0cd59fce3dc00f563c6fa364d67c3f200d278eae681f4dc250240afcfe044b1" +dependencies = [ + "curve25519-dalek", + "solana-zk-sdk", + "thiserror 2.0.18", ] [[package]] name = "spl-token-group-interface" -version = "0.3.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df8752b85a5ecc1d9f3a43bce3dd9a6a053673aacf5deb513d1cbb88d3534ffd" +checksum = "452d0f758af20caaa10d9a6f7608232e000d4c74462f248540b3d2ddfa419776" dependencies = [ "bytemuck", - "solana-program", + "num-derive", + "num-traits", + "num_enum", + "solana-instruction", + "solana-program-error", + "solana-pubkey 3.0.0", "spl-discriminator", "spl-pod", - "spl-program-error", + "thiserror 2.0.18", +] + +[[package]] +name = "spl-token-interface" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c564ac05a7c8d8b12e988a37d82695b5ba4db376d07ea98bc4882c81f96c7f3" +dependencies = [ + "arrayref", + "bytemuck", + "num-derive", + "num-traits", + "num_enum", + "solana-instruction", + "solana-program-error", + "solana-program-option", + "solana-program-pack", + "solana-pubkey 3.0.0", + "solana-sdk-ids", + "thiserror 2.0.18", ] [[package]] name = "spl-token-metadata-interface" -version = "0.4.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6c2318ddff97e006ed9b1291ebec0750a78547f870f62a69c56fe3b46a5d8fc" +checksum = "9c467c7c3bd056f8fe60119e7ec34ddd6f23052c2fa8f1f51999098063b72676" dependencies = [ - "borsh 1.5.1", - "solana-program", + "borsh", + "num-derive", + "num-traits", + "solana-borsh", + "solana-instruction", + "solana-program-error", + "solana-pubkey 3.0.0", "spl-discriminator", "spl-pod", - "spl-program-error", "spl-type-length-value", + "thiserror 2.0.18", ] [[package]] name = "spl-transfer-hook-interface" -version = "0.7.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a110f33d941275d9f868b96daaa993f1e73b6806cc8836e43075b4d3ad8338a7" +checksum = "c34b46b8f39bc64a9ab177a0ea8e9a58826db76f8d9d154a2400ee60baef7b1e" dependencies = [ "arrayref", "bytemuck", - "solana-program", + "num-derive", + "num-traits", + "solana-account-info", + "solana-cpi", + "solana-instruction", + "solana-msg", + "solana-program-error", + "solana-pubkey 3.0.0", + "solana-sdk-ids", + "solana-system-interface 2.0.0", "spl-discriminator", "spl-pod", "spl-program-error", "spl-tlv-account-resolution", "spl-type-length-value", + "thiserror 2.0.18", ] [[package]] name = "spl-type-length-value" -version = "0.5.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdcd73ec187bc409464c60759232e309f83b52a18a9c5610bf281c9c6432918c" +checksum = "ca20a1a19f4507a98ca4b28ff5ed54cac9b9d34ed27863e2bde50a3238f9a6ac" dependencies = [ "bytemuck", - "solana-program", + "num-derive", + "num-traits", + "num_enum", + "solana-account-info", + "solana-msg", + "solana-program-error", "spl-discriminator", "spl-pod", - "spl-program-error", + "thiserror 2.0.18", ] [[package]] -name = "static_assertions" -version = "1.1.0" +name = "stable_deref_trait" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "strsim" @@ -5286,52 +5883,18 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - [[package]] name = "strsim" version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" -[[package]] -name = "strum" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" -dependencies = [ - "strum_macros", -] - -[[package]] -name = "strum_macros" -version = "0.24.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "rustversion", - "syn 1.0.109", -] - [[package]] name = "subtle" version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" -[[package]] -name = "symlink" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7973cce6668464ea31f176d85b13c7ab3bba2cb3b77a2ed26abd7801688010a" - [[package]] name = "syn" version = "1.0.109" @@ -5345,9 +5908,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.72" +version = "2.0.115" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" +checksum = "6e614ed320ac28113fa64972c4262d5dbc89deacdfd00c34a3e4cea073243c12" dependencies = [ "proc-macro2", "quote", @@ -5355,291 +5918,140 @@ dependencies = [ ] [[package]] -name = "syn_derive" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1329189c02ff984e9736652b1631330da25eaa6bc639089ed4915d25446cbe7b" -dependencies = [ - "proc-macro-error", - "proc-macro2", - "quote", - "syn 2.0.72", -] - -[[package]] -name = "sync_wrapper" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" - -[[package]] -name = "synstructure" -version = "0.12.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", - "unicode-xid", -] - -[[package]] -name = "system-configuration" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" -dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "system-configuration-sys", -] - -[[package]] -name = "system-configuration-sys" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "take_mut" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" - -[[package]] -name = "takecell" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20f34339676cdcab560c9a82300c4c2581f68b9369aedf0fae86f2ff9565ff3e" - -[[package]] -name = "tar" -version = "0.4.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb797dad5fb5b76fcf519e702f4a589483b5ef06567f160c392832c1f5e44909" -dependencies = [ - "filetime", - "libc", - "xattr", -] - -[[package]] -name = "tarpc" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c38a012bed6fb9681d3bf71ffaa4f88f3b4b9ed3198cda6e4c8462d24d4bb80" -dependencies = [ - "anyhow", - "fnv", - "futures", - "humantime", - "opentelemetry", - "pin-project", - "rand 0.8.5", - "serde", - "static_assertions", - "tarpc-plugins", - "thiserror", - "tokio", - "tokio-serde", - "tokio-util 0.6.10", - "tracing", - "tracing-opentelemetry", -] - -[[package]] -name = "tarpc-plugins" -version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ee42b4e559f17bce0385ebf511a7beb67d5cc33c12c96b7f4e9789919d9c10f" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "task-local-extensions" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba323866e5d033818e3240feeb9f7db2c4296674e4d9e16b97b7bf8f490434e8" -dependencies = [ - "pin-utils", -] - -[[package]] -name = "teloxide" -version = "0.12.2" +name = "sync_wrapper" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c63345cf32a8850ebddcdd769dc2d5193d5e231262d5dada264b79da01a664da" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" dependencies = [ - "aquamarine 0.1.12", - "bytes", - "derive_more", - "dptree", - "futures", - "log", - "mime", - "pin-project", - "serde", - "serde_json", - "serde_with_macros 1.5.2", - "teloxide-core", - "teloxide-macros", - "thiserror", - "tokio", - "tokio-stream", - "tokio-util 0.7.11", - "url", + "futures-core", ] [[package]] -name = "teloxide-core" -version = "0.9.1" +name = "synstructure" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "303db260110c238e3af77bb9dff18bf7a5b5196f783059b0852aab75f91d5a16" +checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" dependencies = [ - "bitflags 1.3.2", - "bytes", - "chrono", - "derive_more", - "either", - "futures", - "log", - "mime", - "never", - "once_cell", - "pin-project", - "rc-box", - "reqwest", - "serde", - "serde_json", - "serde_with_macros 1.5.2", - "take_mut", - "takecell", - "thiserror", - "tokio", - "tokio-util 0.7.11", - "url", - "uuid", + "proc-macro2", + "quote", + "syn 1.0.109", + "unicode-xid", ] [[package]] -name = "teloxide-macros" -version = "0.7.1" +name = "synstructure" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f1d653b093dba5e44cada57a516f572167df37b8a619443e59c8c517bb6d804" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ - "heck", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.115", ] +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + [[package]] name = "tempfile" -version = "3.11.0" +version = "3.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fcd239983515c23a32fb82099f97d0b11b8c72f654ed659363a95c3dad7a53" +checksum = "0136791f7c95b1f6dd99f9cc786b91bb81c3800b639b3478e561ddb7be95e5f1" dependencies = [ - "cfg-if", "fastrand", + "getrandom 0.4.1", "once_cell", "rustix", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] -name = "termcolor" -version = "1.4.1" +name = "textwrap" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" dependencies = [ - "winapi-util", + "unicode-width 0.1.14", ] [[package]] -name = "termtree" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" - -[[package]] -name = "textwrap" -version = "0.11.0" +name = "thiserror" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ - "unicode-width", + "thiserror-impl 1.0.69", ] [[package]] -name = "textwrap" -version = "0.16.1" +name = "thiserror" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl 2.0.18", +] [[package]] -name = "thiserror" -version = "1.0.63" +name = "thiserror-impl" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ - "thiserror-impl", + "proc-macro2", + "quote", + "syn 2.0.115", ] [[package]] name = "thiserror-impl" -version = "1.0.63" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.115", ] [[package]] -name = "thread_local" -version = "1.1.8" +name = "threadpool" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" dependencies = [ - "cfg-if", - "once_cell", + "num_cpus", ] [[package]] name = "time" -version = "0.3.36" +version = "0.3.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" dependencies = [ "deranged", "itoa", "num-conv", "powerfmt", - "serde", + "serde_core", "time-core", "time-macros", ] [[package]] name = "time-core" -version = "0.1.2" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" [[package]] name = "time-macros" -version = "0.2.18" +version = "0.2.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" dependencies = [ "num-conv", "time-core", @@ -5647,28 +6059,36 @@ dependencies = [ [[package]] name = "tiny-bip39" -version = "0.8.2" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffc59cb9dfc85bb312c3a78fd6aa8a8582e310b0fa885d5bb877f6dcc601839d" +checksum = "a30fd743a02bf35236f6faf99adb03089bb77e91c998dac2c2ad76bb424f668c" dependencies = [ - "anyhow", - "hmac 0.8.1", "once_cell", - "pbkdf2 0.4.0", - "rand 0.7.3", - "rustc-hash", - "sha2 0.9.9", - "thiserror", + "pbkdf2 0.12.2", + "rand 0.8.5", + "rustc-hash 1.1.0", + "sha2", + "thiserror 1.0.69", "unicode-normalization", "wasm-bindgen", "zeroize", ] +[[package]] +name = "tinystr" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" +dependencies = [ + "displaydoc", + "zerovec", +] + [[package]] name = "tinyvec" -version = "1.8.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" +checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" dependencies = [ "tinyvec_macros", ] @@ -5681,11 +6101,10 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.39.2" +version = "1.49.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1" +checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" dependencies = [ - "backtrace", "bytes", "libc", "mio", @@ -5694,61 +6113,35 @@ dependencies = [ "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] name = "tokio-macros" -version = "2.4.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" +checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", -] - -[[package]] -name = "tokio-native-tls" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" -dependencies = [ - "native-tls", - "tokio", + "syn 2.0.115", ] [[package]] name = "tokio-rustls" -version = "0.24.1" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" dependencies = [ "rustls", "tokio", ] -[[package]] -name = "tokio-serde" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "911a61637386b789af998ee23f50aa30d5fd7edcec8d6d3dedae5e5815205466" -dependencies = [ - "bincode", - "bytes", - "educe", - "futures-core", - "futures-sink", - "pin-project", - "serde", - "serde_json", -] - [[package]] name = "tokio-stream" -version = "0.1.15" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" +checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" dependencies = [ "futures-core", "pin-project-lite", @@ -5757,146 +6150,184 @@ dependencies = [ [[package]] name = "tokio-tungstenite" -version = "0.20.1" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" +checksum = "d25a406cddcc431a75d3d9afc6a7c0f7428d4891dd973e4d54c56b46127bf857" dependencies = [ "futures-util", "log", "rustls", + "rustls-pki-types", "tokio", "tokio-rustls", - "tungstenite 0.20.1", - "webpki-roots 0.25.4", -] - -[[package]] -name = "tokio-tungstenite" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c83b561d025642014097b66e6c1bb422783339e0909e4429cde4749d1990bc38" -dependencies = [ - "futures-util", - "log", - "tokio", - "tungstenite 0.21.0", + "tungstenite", + "webpki-roots 0.26.11", ] [[package]] name = "tokio-util" -version = "0.6.10" +version = "0.7.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36943ee01a6d67977dd3f84a5a1d2efeb4ada3a1ae771cadfaa535d9d9fc6507" +checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" dependencies = [ "bytes", "futures-core", "futures-sink", - "log", + "futures-util", "pin-project-lite", - "slab", "tokio", ] [[package]] -name = "tokio-util" -version = "0.7.11" +name = "toml" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", + "serde", + "serde_spanned", + "toml_datetime 0.6.11", + "toml_edit 0.22.27", ] [[package]] -name = "toml" -version = "0.5.11" +name = "toml_datetime" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" dependencies = [ "serde", ] [[package]] name = "toml_datetime" -version = "0.6.8" +version = "0.7.5+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime 0.6.11", + "toml_write", + "winnow", +] [[package]] name = "toml_edit" -version = "0.21.1" +version = "0.23.10+spec-1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269" dependencies = [ - "indexmap 2.3.0", - "toml_datetime", + "indexmap", + "toml_datetime 0.7.5+spec-1.1.0", + "toml_parser", "winnow", ] [[package]] -name = "tower-service" -version = "0.3.2" +name = "toml_parser" +version = "1.0.8+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" +checksum = "0742ff5ff03ea7e67c8ae6c93cac239e0d9784833362da3f9a9c1da8dfefcbdc" +dependencies = [ + "winnow", +] [[package]] -name = "tracing" -version = "0.1.40" +name = "toml_write" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" + +[[package]] +name = "tower" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" dependencies = [ - "log", + "futures-core", + "futures-util", "pin-project-lite", - "tracing-attributes", - "tracing-core", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", ] [[package]] -name = "tracing-attributes" -version = "0.1.27" +name = "tower-http" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.72", + "async-compression", + "bitflags 2.11.0", + "bytes", + "futures-core", + "futures-util", + "http 1.4.0", + "http-body", + "http-body-util", + "iri-string", + "pin-project-lite", + "tokio", + "tokio-util", + "tower", + "tower-layer", + "tower-service", ] [[package]] -name = "tracing-core" -version = "0.1.32" +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ - "once_cell", - "valuable", + "log", + "pin-project-lite", + "tracing-core", ] [[package]] -name = "tracing-opentelemetry" -version = "0.17.4" +name = "tracing-core" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbbe89715c1dbbb790059e2565353978564924ee85017b5fff365c872ff6721f" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" dependencies = [ "once_cell", - "opentelemetry", - "tracing", - "tracing-core", - "tracing-subscriber", ] [[package]] -name = "tracing-subscriber" -version = "0.3.18" +name = "trait-variant" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +checksum = "70977707304198400eb4835a78f6a9f928bf41bba420deb8fdb175cd965d77a7" dependencies = [ - "sharded-slab", - "thread_local", - "tracing-core", + "proc-macro2", + "quote", + "syn 2.0.115", ] [[package]] @@ -5907,91 +6338,68 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "tungstenite" -version = "0.20.1" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" +checksum = "8628dcc84e5a09eb3d8423d6cb682965dea9133204e8fb3efee74c2a0c259442" dependencies = [ - "byteorder", "bytes", "data-encoding", - "http 0.2.12", + "http 1.4.0", "httparse", "log", - "rand 0.8.5", + "rand 0.9.2", "rustls", + "rustls-pki-types", "sha1", - "thiserror", - "url", - "utf-8", - "webpki-roots 0.24.0", -] - -[[package]] -name = "tungstenite" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ef1a641ea34f399a848dea702823bbecfb4c486f911735368f1f137cb8257e1" -dependencies = [ - "byteorder", - "bytes", - "data-encoding", - "http 1.1.0", - "httparse", - "log", - "rand 0.8.5", - "sha1", - "thiserror", - "url", + "thiserror 2.0.18", "utf-8", + "webpki-roots 0.26.11", ] [[package]] name = "typenum" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" - -[[package]] -name = "unicase" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" -dependencies = [ - "version_check", -] - -[[package]] -name = "unicode-bidi" -version = "0.3.15" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "537dd038a89878be9b64dd4bd1b260315c1bb94f4d784956b81e27a088d9a09e" [[package]] name = "unicode-normalization" -version = "0.1.23" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8" dependencies = [ "tinyvec", ] [[package]] name = "unicode-width" -version = "0.1.13" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + +[[package]] +name = "unicode-width" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" [[package]] name = "unicode-xid" -version = "0.2.4" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "unit-prefix" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +checksum = "81e544489bf3d8ef66c953931f56617f423cd4b5494be343d9b9d3dda037b9a3" [[package]] name = "universal-hash" @@ -6018,12 +6426,6 @@ version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" -[[package]] -name = "untrusted" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" - [[package]] name = "untrusted" version = "0.9.0" @@ -6042,9 +6444,9 @@ dependencies = [ [[package]] name = "url" -version = "2.5.2" +version = "2.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" dependencies = [ "form_urlencoded", "idna", @@ -6059,25 +6461,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" [[package]] -name = "uuid" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" -dependencies = [ - "getrandom 0.2.15", -] - -[[package]] -name = "valuable" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" - -[[package]] -name = "vcpkg" -version = "0.2.15" +name = "utf8_iter" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "vec_map" @@ -6118,58 +6505,60 @@ dependencies = [ [[package]] name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" +version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +name = "wasip2" +version = "1.0.2+wasi-0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] [[package]] -name = "wasm-bindgen" -version = "0.2.92" +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 = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" dependencies = [ - "cfg-if", - "wasm-bindgen-macro", + "wit-bindgen", ] [[package]] -name = "wasm-bindgen-backend" -version = "0.2.92" +name = "wasm-bindgen" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566" dependencies = [ - "bumpalo", - "log", + "cfg-if", "once_cell", - "proc-macro2", - "quote", - "syn 2.0.72", + "rustversion", + "wasm-bindgen-macro", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.42" +version = "0.4.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +checksum = "70a6e77fd0ae8029c9ea0063f87c46fde723e7d887703d74ad2616d792e51e6f" dependencies = [ "cfg-if", + "futures-util", "js-sys", + "once_cell", "wasm-bindgen", "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.92" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -6177,71 +6566,105 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.92" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55" dependencies = [ + "bumpalo", "proc-macro2", "quote", - "syn 2.0.72", - "wasm-bindgen-backend", + "syn 2.0.115", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.92" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12" +dependencies = [ + "unicode-ident", +] [[package]] -name = "wasm-streams" -version = "0.4.0" +name = "wasm-encoder" +version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129" +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", + "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.11.0", + "hashbrown 0.15.2", + "indexmap", + "semver", +] + +[[package]] +name = "web-sys" +version = "0.3.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "312e32e551d92129218ea9a2452120f4aabc03529ef03e4d0d82fb2780608598" dependencies = [ - "futures-util", "js-sys", "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", ] [[package]] -name = "web-sys" -version = "0.3.69" +name = "web-time" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" dependencies = [ "js-sys", "wasm-bindgen", ] [[package]] -name = "webpki-roots" -version = "0.24.0" +name = "webpki-root-certs" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b291546d5d9d1eab74f069c77749f2cb8504a12caa20f0f2de93ddbf6f411888" +checksum = "804f18a4ac2676ffb4e8b5b5fa9ae38af06df08162314f96a68d2a363e21a8ca" dependencies = [ - "rustls-webpki", + "rustls-pki-types", ] [[package]] name = "webpki-roots" -version = "0.25.4" +version = "0.26.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" +checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" +dependencies = [ + "webpki-roots 1.0.6", +] [[package]] -name = "which" -version = "4.4.2" +name = "webpki-roots" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +checksum = "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed" dependencies = [ - "either", - "home", - "once_cell", - "rustix", + "rustls-pki-types", ] [[package]] @@ -6262,11 +6685,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.9" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -6275,22 +6698,97 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "wincode" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "466e67917609b2d40a838a5b972d1a6237c9749600cb8de8f65559b90d48485b" +dependencies = [ + "pastey", + "proc-macro2", + "quote", + "thiserror 2.0.18", + "wincode-derive", +] + +[[package]] +name = "wincode-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26a7a568eda854acc9945ed136a9d50b8c6d31911584624958808ae96eee3912" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.115", +] + [[package]] name = "windows-core" -version = "0.52.0" +version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ - "windows-targets 0.52.6", + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", ] [[package]] name = "windows-sys" -version = "0.48.0" +version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" dependencies = [ - "windows-targets 0.48.5", + "windows-targets 0.42.2", ] [[package]] @@ -6311,19 +6809,37 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.5", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-targets" -version = "0.48.5" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" 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", + "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]] @@ -6335,18 +6851,35 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", + "windows_i686_gnullvm 0.52.6", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", "windows_x86_64_msvc 0.52.6", ] +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", +] + [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.5" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" [[package]] name = "windows_aarch64_gnullvm" @@ -6354,11 +6887,17 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + [[package]] name = "windows_aarch64_msvc" -version = "0.48.5" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" [[package]] name = "windows_aarch64_msvc" @@ -6366,11 +6905,17 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + [[package]] name = "windows_i686_gnu" -version = "0.48.5" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" [[package]] name = "windows_i686_gnu" @@ -6378,17 +6923,29 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + [[package]] name = "windows_i686_msvc" -version = "0.48.5" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" [[package]] name = "windows_i686_msvc" @@ -6396,11 +6953,17 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + [[package]] name = "windows_x86_64_gnu" -version = "0.48.5" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" [[package]] name = "windows_x86_64_gnu" @@ -6408,11 +6971,17 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.5" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" [[package]] name = "windows_x86_64_gnullvm" @@ -6420,11 +6989,17 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + [[package]] name = "windows_x86_64_msvc" -version = "0.48.5" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" [[package]] name = "windows_x86_64_msvc" @@ -6432,23 +7007,122 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + [[package]] name = "winnow" -version = "0.5.40" +version = "0.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" dependencies = [ "memchr", ] [[package]] -name = "winreg" -version = "0.50.0" +name = "wit-bindgen" +version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" dependencies = [ - "cfg-if", - "windows-sys 0.48.0", + "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", + "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.11.0", + "indexmap", + "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", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] + +[[package]] +name = "writeable" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", ] [[package]] @@ -6465,86 +7139,156 @@ dependencies = [ "nom", "oid-registry", "rusticata-macros", - "thiserror", + "thiserror 1.0.69", "time", ] [[package]] -name = "xattr" -version = "1.3.1" +name = "yoke" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" dependencies = [ - "libc", - "linux-raw-sys", - "rustix", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", + "synstructure 0.13.2", ] [[package]] name = "zerocopy" -version = "0.7.35" +version = "0.8.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +checksum = "db6d35d663eadb6c932438e763b262fe1a70987f9ae936e60158176d710cae4a" dependencies = [ - "byteorder", "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.35" +version = "0.8.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4122cd3169e94605190e77839c9a40d40ed048d305bfdc146e7df40ab0f3e517" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.115", + "synstructure 0.13.2", ] [[package]] name = "zeroize" -version = "1.3.0" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" dependencies = [ "zeroize_derive", ] [[package]] name = "zeroize_derive" -version = "1.4.2" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "zerotrie" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.115", ] +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" + [[package]] name = "zstd" -version = "0.11.2+zstd.1.5.2" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" +checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" dependencies = [ "zstd-safe", ] [[package]] name = "zstd-safe" -version = "5.0.2+zstd.1.5.2" +version = "7.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" +checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d" dependencies = [ - "libc", "zstd-sys", ] [[package]] name = "zstd-sys" -version = "2.0.13+zstd.1.5.6" +version = "2.0.16+zstd.1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" +checksum = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748" dependencies = [ "cc", "pkg-config", diff --git a/Cargo.toml b/Cargo.toml index e7c4e38..1439406 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,37 +1,129 @@ [package] name = "sniper" version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[profile.release] -opt-level = 3 +edition = "2024" +license = "MIT" [dependencies] futures-util = "0.3.30" -reqwest = { version = "0.11.24", features = ["json", "rustls-tls"], default-features = false } serde = { version = "1.0.197", features = ["derive"] } serde_json = "1.0.115" -solana-client = "2.0.4" -solana-sdk = { version = "2.0.4", features = ["full"] } +solana-client = "3.1.8" +solana-sdk = { version = "3.0.0", features = ["full"] } +solana-commitment-config = "3.1.0" +solana-compute-budget-interface = "3.0.0" +solana-system-interface = { version = "3.0.0", features = ["bincode", "std"] } tokio = { version = "1.36.0", features = ["full"] } -tokio-tungstenite = "0.21.0" -dotenv = "0.15.0" log = "0.4" -solana-transaction-status = "2.0.4" +solana-transaction-status = "3.1.8" colored = "2.1.0" -teloxide = { version = "0.12", features = ["macros"] } -solana-account-decoder = "2.0.4" -spl-token = "6.0.0" -spl-token-client = "0.11.0" -spl-associated-token-account = "4.0.0" +solana-account-decoder = "3.1.8" +spl-token = "9.0.0" +spl-token-client = "0.18.0" +spl-associated-token-account = "8.0.0" byteorder = "1.4" arrayref = "0.3" base64 = "0.22.1" futures = "0.3.30" -regex = "1.10.4" chrono = "0.4.37" bs58 = "0.5.1" borsh = "1.5.1" fern = { version = "0.6.2", features = ["colored"] } +trait-variant = "0.1.2" +toml = "0.8.19" + +[profile.release] +opt-level = 3 +lto = "thin" +codegen-units = 1 +panic = "abort" +strip = "symbols" + +[profile.dev] +debug = 2 +opt-level = 0 +overflow-checks = true +incremental = false +panic = "unwind" +lto = false + +[features] +fuzzing = [] +legacy-charts = [] + +[lints.rust] +rust_2024_prelude_collisions = "warn" +rust_2024_incompatible_pat = "warn" +rust_2024_guarded_string_incompatible_syntax = "warn" +deprecated_safe_2024 = "warn" + +[lints.clippy] +allow_attributes = "deny" +unwrap_used = "deny" +expect_used = "deny" +inefficient_to_string = "deny" +todo = "deny" +unimplemented = "deny" +panic = "deny" +result_large_err = "deny" +map_err_ignore = "deny" +unreachable = "deny" +dbg_macro = "deny" +ignored_unit_patterns = "deny" +await_holding_refcell_ref = "deny" +match_bool = "deny" +if_same_then_else = "deny" +needless_pass_by_value = "deny" +borrowed_box = "deny" +str_to_string = "deny" +filter_map_next = "deny" +iter_not_returning_iterator = "deny" +needless_collect = "deny" +wildcard_enum_match_arm = "deny" +missing_errors_doc = "deny" +missing_panics_doc = "deny" +undocumented_unsafe_blocks = "deny" +let_underscore_must_use = "deny" +must_use_candidate = "deny" +match_wild_err_arm = "deny" +indexing_slicing = "deny" +panic_in_result_fn = "deny" +unwrap_in_result = "deny" +missing_const_for_fn = "deny" +implicit_clone = "deny" +redundant_clone = "deny" +lossy_float_literal = "deny" +unnecessary_wraps = "deny" +map_flatten = "deny" +or_fun_call = "deny" +ok_expect = "deny" +await_holding_lock = "deny" +mutex_atomic = "deny" +needless_borrow = "deny" +wildcard_dependencies = "deny" +enum_glob_use = "deny" +match_ref_pats = "deny" +wrong_self_convention = "deny" +trivially_copy_pass_by_ref = "deny" +ptr_arg = "deny" +needless_lifetimes = "deny" +mutable_key_type = "deny" +large_enum_variant = "deny" +vec_box = "deny" +float_cmp = "deny" +bool_assert_comparison = "deny" +cmp_owned = "deny" +string_add = "deny" +assertions_on_constants = "deny" +useless_asref = "deny" +shadow_unrelated = "deny" +arithmetic_side_effects = "deny" +float_arithmetic = "deny" +box_collection = "deny" +unnecessary_box_returns = "deny" +trait_duplication_in_bounds = "deny" +single_char_lifetime_names = "deny" +format_push_string = "deny" +option_if_let_else = "deny" +manual_string_new = "deny" +flat_map_option = "deny" diff --git a/Makefile.toml b/Makefile.toml new file mode 100644 index 0000000..b0407cb --- /dev/null +++ b/Makefile.toml @@ -0,0 +1,185 @@ +[env] +CARGO_NET_OFFLINE = "true" + +[tasks.build] +description = "Build all projects" +workspace = false +command = "cargo" +args = ["build", "--all-features", "${@}"] +dependencies = ["clean"] + +[tasks.format] +description = "Format code using rustfmt" +workspace = false +command = "cargo" +args = ["fmt", "--all"] + +[tasks.format-check] +description = "Verify code formatting with rustfmt" +workspace = false +command = "cargo" +args = ["fmt", "--check", "--all"] + +[tasks.file] +description = "Fast local file-level validation (format + compile check)" +workspace = false +command = "cargo" +args = ["check", "--offline", "--workspace", "--all-targets", "${@}"] + +[tasks.clean] +description = "Remove build artifacts" +command = "cargo" +args = ["clean", "${@}"] + +[tasks.bacon] +description = "Live code checking with bacon" +workspace = false +dependencies = ["check-bacon"] +command = "bacon" +args = ["${@}", "check-all"] + +[tasks.build-prod] +description = "Build optimized release binaries" +workspace = false +command = "cargo" +args = ["build", "--release", "${@}"] +dependencies = ["clean"] + +[tasks.check] +description = "Quick compilation check without building" +workspace = false +command = "cargo" +args = ["check", "--workspace", "--all", "${@}"] + +[tasks.architecture-check] +description = "Enforce architecture boundaries and print coupling metrics" +workspace = false +command = "bash" +args = ["scripts/check_architecture.sh"] + +[tasks.fuzz] +description = "Run fuzzing tests on specified targets" +workspace = false +dependencies = ["fuzz-check-tools"] +command = "cargo" +args = ["+nightly", "fuzz", "${@}"] + +[tasks.fuzz-all] +description = "Run all fuzz targets sequentially" +workspace = false +dependencies = ["fuzz-check-tools"] +command = "bash" +args = ["fuzz/run_all.sh", "${@}"] + +[tasks.fuzz-check-tools] +description = "Verify fuzzing toolchain (cargo-fuzz + nightly) is installed" +workspace = false +command = "bash" +args = ["fuzz/check_tools.sh"] + +[tasks.test] +description = "Run all tests with nextest" +workspace = false +dependencies = ["check-nextest"] +command = "cargo" +args = ["nextest", "run", "--workspace", "${@}"] + +[tasks.clippy] +description = "Run clippy with strict rules on all targets except fuzz" +workspace = false +command = "cargo" +args = [ + "clippy", + "--all-targets", + "--locked", + "--", + "-D", + "warnings", + "${@}", +] + +[tasks.deny] +description = "Check licenses and security advisories" +workspace = false +dependencies = ["check-deny"] +command = "cargo" +args = ["deny", "check"] + +[tasks.audit] +description = "Security audit for dependencies" +workspace = false +dependencies = ["check-audit"] +command = "cargo" +args = ["audit", "${@}"] + +[tasks.replay-benchmark] +description = "Run synthetic burst replay benchmark (FPGA vs kernel-bypass)" +workspace = false +command = "cargo" +args = ["run", "--release", "--", "--config", "sniper.toml", "--replay-benchmark", "${@}"] + +[tasks.run-sniper] +description = "Run sniper and forward CLI args (example: --config /path/sniper.toml)" +workspace = false +command = "cargo" +args = ["run", "--release", "--", "${@}"] + +[tasks.devnet-smoke] +description = "Create/fund devnet keypair and run direct-mode smoke snipe from TOML config" +workspace = false +command = "bash" +args = ["scripts/devnet_bootstrap_and_snipe.sh", "${@}"] + +[tasks.devnet-auto-snipe] +description = "Alias for devnet-smoke" +workspace = false +command = "bash" +args = ["scripts/devnet_bootstrap_and_snipe.sh", "${@}"] + +[tasks.service-install] +description = "Install and start systemd service via internal CLI flags" +workspace = false +command = "cargo" +args = ["run", "--release", "--", "--install-service", "${@}"] + +[tasks.service-uninstall] +description = "Stop and uninstall systemd service via internal CLI flags" +workspace = false +command = "cargo" +args = ["run", "--release", "--", "--uninstall-service", "${@}"] + +[tasks.check-nextest] +description = "Verify cargo-nextest is installed" +workspace = false +command = "bash" +args = [ + "-c", + "if ! cargo nextest --version >/dev/null 2>&1; then echo 'cargo-nextest is required. Install once with: CARGO_NET_OFFLINE=false cargo install cargo-nextest' >&2; exit 1; fi", +] + +[tasks.check-audit] +description = "Verify cargo-audit is installed" +workspace = false +command = "bash" +args = [ + "-c", + "if ! cargo audit --version >/dev/null 2>&1; then echo 'cargo-audit is required. Install once with: CARGO_NET_OFFLINE=false cargo install cargo-audit' >&2; exit 1; fi", +] + +[tasks.check-deny] +description = "Verify cargo-deny is installed" +workspace = false +command = "bash" +args = [ + "-c", + "if ! cargo deny --version >/dev/null 2>&1; then echo 'cargo-deny is required. Install once with: CARGO_NET_OFFLINE=false cargo install cargo-deny' >&2; exit 1; fi", +] + +[tasks.check-bacon] +description = "Verify bacon is installed" +workspace = false +command = "bash" +args = [ + "-c", + "if ! bacon --version >/dev/null 2>&1; then echo 'bacon is required. Install once with: CARGO_NET_OFFLINE=false cargo install bacon' >&2; exit 1; fi", +] diff --git a/README.md b/README.md index 44e4f87..9a2515d 100644 --- a/README.md +++ b/README.md @@ -1,32 +1,266 @@ -## Advanced Solana Sniper by MINT CA and Deployer address +# DeGeneRate Solana Sniper +High-performance Solana sniper focused on Raydium pool creation events. -This sniper is written in rust for speed and safety. -The sniper also has a reduced amount of rpc calls to increase speed -of sniping right after catching pool creation in ``confirmed`` commitment. -Sniping is being done with jito to increase the likelyhood of success. +## Scope -It can snipe only raydium pools: -- OpenBook -- CPMM +- Supported pools: + - Raydium OpenBook + - Raydium CPMM +- Rule targeting: + - Mint address + - Deployer address +- Transaction submission modes: + - `jito` + - `direct` +- Ingress path failover (log/event intake): + - FPGA DMA (primary) + - Kernel bypass feed path (secondary) + - Standard TCP websocket feed path (fallback) -## How to use it +## Configuration Model -1. Copy ``.env.example`` and rename it to ``.env`` -2. paste the rpc and wss url in ``.env`` -3. Generate a keypair.json with solana cli -4. Deposit some SOL in the new generated wallet -5. Now set the MINT CA into mints.txt in ``addys/mints|snipe height|jito tip|slippage`` format or - ``account address|snipe height|jito tip|slippage`` in deployers.txt to snipe by deployer. -6. Ensure that Rust and ``cargo`` are installed. -7. Start the sniper with ``cargo run --release`` +This project is TOML-only. `.env` is not used by runtime configuration. -## Disclaimer +1. Copy `sniper.example.toml` to `sniper.toml`. +2. Edit the runtime and rule sections. +3. Start the binary with `--config`. + +Minimal example: + +```toml +[runtime] +keypair_path = "keypair.json" +rpc_url = "https://api.mainnet-beta.solana.com" +wss_url = "wss://api.mainnet-beta.solana.com" +priority_fees = 1000000 +tx_submission_mode = "jito" +jito_url = "https://amsterdam.mainnet.block-engine.jito.wtf/api/v1/transactions?bundleOnly=true" +kernel_tcp_bypass = true +kernel_tcp_bypass_engine = "af_xdp_or_dpdk_external" +kernel_bypass_socket_path = "/tmp/sniper-kernel-bypass.sock" + +[telemetry] +enabled = true +sample_capacity = 4096 +slo_ns = 1000000 +report_period_secs = 15 + +[[rules]] +kind = "mint" +address = "So11111111111111111111111111111111111111112" +snipe_height_sol = "0.01" +tip_budget_sol = "0.001" +slippage_pct = "1" + +[[rules]] +kind = "mint" +address = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" +snipe_height_sol = "0.01" +tip_budget_sol = "0.001" +slippage_pct = "1" +``` + +## Config Reference + +`[runtime]`: + +- `keypair_path`: path to Solana keypair JSON. +- `rpc_url`: HTTP RPC URL. +- `wss_url`: websocket URL. +- `priority_fees`: microlamports. +- `tx_submission_mode`: `jito` or `direct`. +- `jito_url`: required when `tx_submission_mode = "jito"`. +- `kernel_tcp_bypass`: enable kernel bypass path. +- `kernel_tcp_bypass_engine`: `af_xdp`, `dpdk`, `openonload`, `af_xdp_or_dpdk_external`. +- `kernel_bypass_socket_path`: unix socket for external AF_XDP/DPDK bypass feed bridge. +- `fpga_enabled`: force FPGA ingress if available. +- `fpga_verbose`: verbose FPGA diagnostics. +- `fpga_vendor`: vendor label. +- `replay_benchmark`: run synthetic replay instead of live strategy. +- `replay_event_count`: replay event count. +- `replay_burst_size`: replay burst size. + +`[telemetry]`: + +- `enabled`: if `false`, telemetry sampling/reporter logs are disabled. +- `sample_capacity`: per-hop sample buffer size. +- `slo_ns`: SLO threshold in nanoseconds. +- `report_period_secs`: telemetry report interval. + +`[[rules]]`: + +- `kind`: `mint` or `deployer`. +- `address`: target pubkey. +- `snipe_height_sol`: SOL amount string. +- `tip_budget_sol`: SOL amount string. +- `slippage_pct`: percent string. + +Note: monetary/percentage rule values are strings and parsed via fixed-point/integer-safe logic to avoid float drift. + +Multiple mint addresses: + +Use one `[[rules]]` block per mint address (the `rules` section is an array of tables). + +```toml +[[rules]] +kind = "mint" +address = "So11111111111111111111111111111111111111112" +snipe_height_sol = "0.01" +tip_budget_sol = "0.001" +slippage_pct = "1" + +[[rules]] +kind = "mint" +address = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" +snipe_height_sol = "0.02" +tip_budget_sol = "0.001" +slippage_pct = "1.5" +``` + +What telemetry is: + +Telemetry is internal latency instrumentation for core pipeline hops: + +- ingress to engine (`ingress_to_engine_ns`) +- engine classification (`engine_classification_ns`) +- strategy dispatch (`strategy_dispatch_ns`) + +How telemetry is shown: + +- periodic `info` logs: `Latency telemetry > hop=... count=... p50=... p99=... max=...` +- `warn` logs on SLO breaches: `Latency SLO alert > ...` +- under systemd, view via `journalctl -u ` + +Disable telemetry completely: + +```toml +[telemetry] +enabled = false +``` + +When disabled, no telemetry samples or telemetry report lines are emitted. + +External kernel-bypass bridge frame format (newline-delimited JSON on unix socket): + +```json +{"signature":"...","logs":["..."],"has_error":false,"hardware_timestamp_ns":1700000000,"received_timestamp_ns":1700000100} +``` + +## Run + +Direct: + +```bash +cargo run --release -- --config sniper.toml +``` + +Via cargo-make: + +```bash +cargo make run-sniper -- --config sniper.toml +``` -I am not liable for any losses nor wins caused by this program. -Please use at your own risk. I am not responsible for any damages. +Useful runtime flags: -## PS +- `--config ` +- `--replay-benchmark` +- `--fpga` +- `--fpga-verbose` -On further request I can improve the README and how to use the sniper as a linux service in the background with systemd. +If you set `kernel_tcp_bypass_engine = "openonload"`, run under Onload (or equivalent preload setup) to activate acceleration. + +Note: ingress feed transport and tx submission transport are separate concerns. +Ingress can use FPGA/kernel-bypass/websocket, while tx submission uses `direct` RPC or `jito` based on `tx_submission_mode`. + +## Linux systemd + +Service registration is built into the binary. + +Install + enable + start: + +```bash +sudo cargo run --release -- --install-service --config /home/sniper/sniper/sniper.toml +``` + +Uninstall: + +```bash +sudo cargo run --release -- --uninstall-service +``` + +Optional install flags: + +- `--service-name ` (default `sniper`) +- `--service-user ` (default from `SUDO_USER`/`USER`) +- `--service-group ` (default user primary group) +- `--systemd-dir ` (default `/etc/systemd/system`) +- `--no-enable` (write unit only, do not enable/start) + +Cargo-make wrappers: + +```bash +sudo cargo make service-install -- --config /home/sniper/sniper/sniper.toml +sudo cargo make service-uninstall +``` + +## Devnet Smoke Test + +Runs a usability smoke pass using direct submission (no Jito dependency). + +```bash +cargo make devnet-smoke +``` + +Auto bootstrap (creates keypair, attempts funding to 1 SOL, then runs smoke): + +```bash +cargo make devnet-auto-snipe +``` + +Optional environment overrides: + +- `CONFIG_PATH` +- `DEVNET_TARGET_MINT` +- `KEYPAIR_PATH` +- `DEVNET_RPC_URL` +- `DEVNET_WSS_URL` +- `SMOKE_TIMEOUT_SECS` + +If automatic airdrop is rate-limited, the script prompts manual funding via `https://faucet.solana.com`. + +## Quality Gates + +- Tests (nextest): `cargo make test` +- Clippy (deny warnings): `cargo make clippy` +- Cargo deny: `cargo make deny` +- Fuzz all targets: `cargo make fuzz-all` + +Fuzz prerequisites (one-time): + +- `CARGO_NET_OFFLINE=false cargo install cargo-fuzz` +- `rustup toolchain install nightly` + +## Benchmarking + +Synthetic replay benchmark: + +```bash +cargo make replay-benchmark +``` + +Tune with: + +- `runtime.replay_event_count` +- `runtime.replay_burst_size` + +## Documentation + +- Runtime architecture: `docs/architecture/runtime.md` +- On-call playbook: `docs/runbooks/oncall.md` +- Contribution guide: `CONTRIBUTING.md` +- FPGA NIC deployment/PTP/rollback: `docs/operations/fpga_nic_deployment.md` + +## Disclaimer +Use at your own risk. You are responsible for all trading decisions, infrastructure security, and financial outcomes. diff --git a/clippy.toml b/clippy.toml new file mode 100644 index 0000000..42441bc --- /dev/null +++ b/clippy.toml @@ -0,0 +1,15 @@ +type-complexity-threshold = 250 +too-many-arguments-threshold = 6 +enum-variant-name-threshold = 3 +doc-valid-idents = [".."] +avoid-breaking-exported-api = false +single-char-binding-names-threshold = 3 +too-many-lines-threshold = 100 +large-error-threshold = 256 +pass-by-value-size-limit = 256 +stack-size-threshold = 512000 +cognitive-complexity-threshold = 25 +max-struct-bools = 3 +max-fn-params-bools = 3 +disallowed-names = ["foo", "bar", "baz", "todo", "temp", "tmp"] +warn-on-all-wildcard-imports = true diff --git a/deny.toml b/deny.toml new file mode 100644 index 0000000..ce5b8d3 --- /dev/null +++ b/deny.toml @@ -0,0 +1,49 @@ +# cargo-deny configuration +# https://embarkstudios.github.io/cargo-deny/ + +[graph] +all-features = true + +[advisories] +ignore = [ + # Legacy Solana CLI transitive dependencies with no safe upgrade path in current Solana stack. + "RUSTSEC-2021-0139", # ansi_term unmaintained + "RUSTSEC-2021-0145", # atty unsound on windows + "RUSTSEC-2024-0375", # atty unmaintained + "RUSTSEC-2025-0141", # bincode unmaintained +] + +[licenses] +confidence-threshold = 0.93 +include-dev = false +private = { ignore = true } + +allow = [ + "MIT", + "Apache-2.0", + "Apache-2.0 WITH LLVM-exception", + "BSD-2-Clause", + "BSD-3-Clause", + "ISC", + "Zlib", + "0BSD", + "Unlicense", + "Unicode-3.0", + "BSL-1.0", + "LGPL-2.1-or-later", + "MPL-2.0", + "CDLA-Permissive-2.0", +] + +[[licenses.clarify]] +name = "ring" +expression = "MIT AND ISC AND OpenSSL" +license-files = [{ path = "LICENSE", hash = 0xbd0eed23 }] + +[bans] +multiple-versions = "allow" +wildcards = "allow" + +[sources] +unknown-registry = "warn" +unknown-git = "warn" diff --git a/deployers.txt b/deployers.txt deleted file mode 100644 index a9c675c..0000000 --- a/deployers.txt +++ /dev/null @@ -1,3 +0,0 @@ -# Account addresses which will deploy tokens to raydium (account address|snipe height|jito tip|slippage -> per line) to snipe -# (snipe height, jito tip and slippage can be a number and a float) - diff --git a/docs/architecture/runtime.md b/docs/architecture/runtime.md new file mode 100644 index 0000000..3eb522b --- /dev/null +++ b/docs/architecture/runtime.md @@ -0,0 +1,76 @@ +# Runtime Architecture + +## Design Summary + +The runtime uses hexagonal boundaries with vertical slices: + +1. `ports/`: external contracts. +2. `adapters/`: transport and persistence implementations. +3. `domain/`: settings, events, rules, value objects. +4. `slices/`: business flows (`config_sync`, `sniper`). +5. `app/`: bootstrap and composition root. + +## Ingress Topology + +Ingress failover chain: + +1. FPGA DMA path (primary). +2. Kernel-bypass feed path (secondary). +3. Standard TCP websocket feed path (tertiary). + +Bootstrap selects the first healthy path and logs selection explicitly. +Ingress feed transport is separate from tx submission transport (`direct` RPC vs `jito`). + +`runtime.kernel_tcp_bypass_engine` supports `af_xdp`, `dpdk`, `openonload`, and `af_xdp_or_dpdk_external`. +For `openonload`, launch the process under Onload (or equivalent preload configuration) so socket acceleration is active. +For AF_XDP/DPDK bridge mode, provide `runtime.kernel_bypass_socket_path` and stream newline-delimited JSON frames over a unix socket. + +## Event Lifecycle + +1. Ingress adapter emits `RawLogEvent`. +2. Event carries `IngressMetadata`: + - source path + - receive timestamp + - optional hardware timestamp + - normalized nanosecond timestamp +3. `SniperEngine` classifies candidate pool-creation events. +4. Candidate events dispatch into slice handlers (`cpmm`, `openbook`). + +## Deterministic Filtering + +FPGA ingress applies deterministic byte-level prefiltering before payload decode: + +1. OpenBook candidate requires Raydium V4 program marker and `initialize2`. +2. CPMM candidate requires standard AMM marker and excludes swap/fee/burn markers. + +This reduces decode and scheduling overhead for non-candidate traffic. + +## Latency Telemetry + +Per-hop telemetry tracks: + +1. `ingress_to_engine_ns` +2. `engine_classification_ns` +3. `strategy_dispatch_ns` + +Reporter emits P50/P99/max and logs SLO alerts when P99 or max exceeds 1 ms (default). +Set `[telemetry].enabled = false` to fully disable telemetry sampling/report output. + +## Replay Harness + +Synthetic replay mode benchmarks burst ingestion of FPGA-style payloads and kernel-bypass log events: + +```bash +cargo run --release -- --config sniper.toml --replay-benchmark +``` + +Tune with: + +1. `runtime.replay_event_count` +2. `runtime.replay_burst_size` + +## Boundary Rules + +1. `slices` can depend on `domain` and `ports`. +2. `adapters` implement `ports` but do not import `app`. +3. `domain` is dependency-safe and contains no adapter logic. diff --git a/docs/operations/fpga_nic_deployment.md b/docs/operations/fpga_nic_deployment.md new file mode 100644 index 0000000..7cecdb2 --- /dev/null +++ b/docs/operations/fpga_nic_deployment.md @@ -0,0 +1,105 @@ +# FPGA NIC Deployment, PTP Sync, and Rollback + +## Scope + +This runbook covers: + +1. FPGA NIC firmware deployment. +2. PTP clock synchronization verification. +3. Safe rollback to previous firmware and transport path. + +## Preconditions + +1. Maintenance window approved. +2. Out-of-band access to host (IPMI/ILO or console). +3. Backup of current NIC firmware image and toolchain. +4. `runtime.kernel_tcp_bypass = true` and `runtime.fpga_enabled = false` available as immediate fallback. +5. Latest known-good `sniper.toml` copy stored before changes. + +## Deployment Steps + +1. Stop sniper service: +```bash +systemctl stop sniper +``` + +2. Capture baseline state: +```bash +ethtool -i +phc_ctl /dev/ptp0 get +``` + +3. Flash FPGA NIC firmware using vendor tooling: +```bash + flash --device --image +``` + +4. Reboot host if vendor requires reboot for bitstream activation. + +5. Verify firmware activation: +```bash +ethtool -i + status --device +``` + +6. Enable FPGA path in `sniper.toml` under `[runtime]`: +```bash +fpga_enabled = true +fpga_vendor = "" +fpga_verbose = false +``` + +7. Start service and confirm ingress: +```bash +systemctl start sniper +journalctl -u sniper -f +``` + +Expected logs include `Ingress path selected: FPGA DMA ring`. + +## PTP Clock Sync Validation + +1. Start/verify `ptp4l` and `phc2sys`: +```bash +systemctl status ptp4l +systemctl status phc2sys +``` + +2. Validate drift is within target: +```bash +pmc -u -b 0 'GET TIME_STATUS_NP' +phc_ctl /dev/ptp0 cmp +``` + +3. Reject deployment if offset exceeds 1 ms for sustained intervals. + +## Rollback Procedure + +1. Switch runtime path to non-FPGA immediately in `sniper.toml` `[runtime]`: +```bash +fpga_enabled = false +kernel_tcp_bypass = true +``` + +2. Restart service: +```bash +systemctl restart sniper +``` + +3. If firmware issue persists, flash previous known-good image: +```bash + flash --device --image +``` + +4. Re-validate NIC and PTP health with commands from sections above. + +5. Record incident timeline and attach logs from: +```bash +journalctl -u sniper --since "30 min ago" +``` + +## Post-Change Checks + +1. Confirm no continuous `Latency SLO alert` warnings. +2. Confirm strategy event ingestion is uninterrupted for 15 minutes. +3. Document firmware version, host, operator, and rollback readiness in change ticket. diff --git a/docs/runbooks/oncall.md b/docs/runbooks/oncall.md new file mode 100644 index 0000000..a2a0c7c --- /dev/null +++ b/docs/runbooks/oncall.md @@ -0,0 +1,78 @@ +# On-Call Runbook + +## Alert Categories + +1. `Latency SLO alert` (P99/max above threshold). +2. Ingress failover warnings (`FPGA ingress unavailable`, `Kernel bypass ingress unavailable`). +3. Swap execution failures (transaction send/status errors). + +## First 5 Minutes + +1. Confirm active ingress path: +```bash +journalctl -u sniper -n 200 | rg "Ingress path selected|ingress unavailable" +``` + +2. Check latency telemetry trends: +```bash +journalctl -u sniper -n 400 | rg "Latency telemetry|Latency SLO alert" +``` +If no telemetry lines appear, verify `[telemetry].enabled` in `sniper.toml`. + +3. Validate RPC and websocket reachability from host. + +## Ingress Path Incidents + +### FPGA Path Degraded + +1. Verify NIC/PTP health. +2. If unstable, set in `sniper.toml` `[runtime]`: +```bash +fpga_enabled=false +kernel_tcp_bypass=true +``` +3. Restart service. + +### Kernel Bypass Unavailable + +1. Validate `runtime.kernel_tcp_bypass_engine`. + Supported values: `af_xdp`, `dpdk`, `openonload`, `af_xdp_or_dpdk_external`. +2. If AF_XDP/DPDK external bridge mode is selected, verify `runtime.kernel_bypass_socket_path` exists and producer is running. +3. If unsupported or degraded, set in `sniper.toml` `[runtime]`: +```bash +kernel_tcp_bypass=false +``` +4. Restart service; runtime will use standard TCP. + +## Latency Spike Playbook + +1. Confirm whether spike is ingress-only or dispatch-wide using hop metrics. +2. Reduce external contention: + - isolate host CPU + - verify NIC IRQ pinning + - reduce noisy background workloads +3. If unresolved, force fallback to simpler path and compare telemetry. + +## Replay Benchmark for Diagnostics + +Use synthetic harness to compare local path characteristics: + +```bash +cargo run --release -- --config sniper.toml --replay-benchmark +``` + +If FPGA path underperforms kernel-bypass path in replay, treat as ingress processing regression. + +## Escalation + +Escalate to infra/network team when: + +1. Repeated FPGA initialization failures. +2. PTP drift above 1 ms for more than 5 minutes. +3. Both kernel bypass and standard stream startup fail. + +## Incident Closure Checklist + +1. Confirm stable ingress path for 15 minutes. +2. Confirm no active SLO alerts for 15 minutes. +3. Document root cause, mitigation, and follow-up action items. diff --git a/fuzz/.gitignore b/fuzz/.gitignore new file mode 100644 index 0000000..fe68c97 --- /dev/null +++ b/fuzz/.gitignore @@ -0,0 +1,4 @@ +target/ +corpus/ +artifacts/ +coverage/ diff --git a/fuzz/Cargo.lock b/fuzz/Cargo.lock new file mode 100644 index 0000000..110c32e --- /dev/null +++ b/fuzz/Cargo.lock @@ -0,0 +1,8074 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "Inflector" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" +dependencies = [ + "lazy_static", + "regex", +] + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common", + "generic-array", +] + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "aes-gcm-siv" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae0784134ba9375416d469ec31e7c5f9fa94405049cf08c5ce5b4698be673e0d" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "polyval", + "subtle", + "zeroize", +] + +[[package]] +name = "agave-feature-set" +version = "3.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2846bb4fc0831d112255193a54259fabdc82149f0cd0a72db8922837cc62c0cd" +dependencies = [ + "ahash", + "solana-epoch-schedule", + "solana-hash 3.1.0", + "solana-pubkey 3.0.0", + "solana-sha256-hasher", + "solana-svm-feature-set", +] + +[[package]] +name = "agave-reserved-account-keys" +version = "3.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a55fff3d170fbcf81afc8d30c504a1ae4a6ff64be025ee6c08012f3db2a243fc" +dependencies = [ + "agave-feature-set", + "solana-pubkey 3.0.0", + "solana-sdk-ids", +] + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "alloc-no-stdlib" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +dependencies = [ + "alloc-no-stdlib", +] + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "ansi_term" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +dependencies = [ + "winapi", +] + +[[package]] +name = "anyhow" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0e0fee31ef5ed1ba1316088939cea399010ed7731dba877ed44aeb407a75ea" + +[[package]] +name = "aquamarine" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a941c39708478e8eea39243b5983f1c42d2717b3620ee91f4a52115fd02ac43f" +dependencies = [ + "itertools 0.9.0", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "arbitrary" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" + +[[package]] +name = "arc-swap" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9f3647c145568cec02c42054e07bdf9a5a698e15b466fb2341bfc393cd24aa5" +dependencies = [ + "rustversion", +] + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "ascii" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eab1c04a571841102f5345a8fc0f6bb3d31c315dec879b5c6e42e40ce7ffa34e" + +[[package]] +name = "asn1-rs" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6fd5ddaf0351dff5b8da21b2fb4ff8e08ddd02857f0bf69c47639106c0fff0" +dependencies = [ + "asn1-rs-derive", + "asn1-rs-impl", + "displaydoc", + "nom", + "num-traits", + "rusticata-macros", + "thiserror 1.0.69", + "time", +] + +[[package]] +name = "asn1-rs-derive" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "726535892e8eae7e70657b4c8ea93d26b8553afb1ce617caee529ef96d7dee6c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", + "synstructure 0.12.6", +] + +[[package]] +name = "asn1-rs-impl" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2777730b2039ac0f95f093556e61b6d26cebed5393ca6f152717777cec3a42ed" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "async-compression" +version = "0.4.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68650b7df54f0293fd061972a0fb05aaf4fc0879d3b3d21a638a182c5c543b9f" +dependencies = [ + "compression-codecs", + "compression-core", + "pin-project-lite", + "tokio", +] + +[[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-trait" +version = "0.1.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64ct" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" +dependencies = [ + "serde_core", +] + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "blake3" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2468ef7d57b3fb7e16b576e8377cdbde2320c60e1491e961d11da40fc4f02a2d" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", + "cpufeatures", + "digest", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "blst" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcdb4c7013139a150f9fc55d123186dbfaba0d912817466282c73ac49e71fb45" +dependencies = [ + "cc", + "glob", + "threadpool", + "zeroize", +] + +[[package]] +name = "blstrs" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a8a8ed6fefbeef4a8c7b460e4110e12c5e22a5b7cf32621aae6ad650c4dcf29" +dependencies = [ + "blst", + "byte-slice-cast", + "ff", + "group", + "pairing", + "rand_core 0.6.4", + "serde", + "subtle", +] + +[[package]] +name = "borsh" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1da5ab77c1437701eeff7c88d968729e7766172279eab0676857b3d63af7a6f" +dependencies = [ + "borsh-derive", + "cfg_aliases", +] + +[[package]] +name = "borsh-derive" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0686c856aa6aac0c4498f936d7d6a02df690f614c03e4d906d1018062b5c5e2c" +dependencies = [ + "once_cell", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "brotli" +version = "8.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bd8b9603c7aa97359dbd97ecf258968c95f3adddd6db2f7e7a5bef101c84560" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + +[[package]] +name = "bs58" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "bumpalo" +version = "3.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" + +[[package]] +name = "bv" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8834bb1d8ee5dc048ee3124f2c7c1afcc6bc9aed03f11e9dfd8c69470a5db340" +dependencies = [ + "feature-probe", + "serde", +] + +[[package]] +name = "byte-slice-cast" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7575182f7272186991736b70173b0ea045398f984bf5ebbb3804736ce1330c9d" + +[[package]] +name = "bytemuck" +version = "1.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" +dependencies = [ + "serde", +] + +[[package]] +name = "caps" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd1ddba47aba30b6a889298ad0109c3b8dcb0e8fc993b459daa7067d46f865e0" +dependencies = [ + "libc", +] + +[[package]] +name = "cc" +version = "1.2.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" +dependencies = [ + "find-msvc-tools", + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[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 = "cfg_eval" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45565fc9416b9896014f5732ac776f810ee53a66730c17e4020c3ec064a8f88f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "chrono" +version = "0.4.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fac4744fb15ae8337dc853fee7fb3f4e48c0fbaa23d0afe49c447b4fab126118" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-link", +] + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + +[[package]] +name = "clap" +version = "2.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" +dependencies = [ + "ansi_term", + "atty", + "bitflags 1.3.2", + "strsim 0.8.0", + "textwrap", + "unicode-width 0.1.14", + "vec_map", +] + +[[package]] +name = "colored" +version = "1.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f741c91823341bebf717d4c71bda820630ce065443b58bd1b7451af008355" +dependencies = [ + "is-terminal", + "lazy_static", + "winapi", +] + +[[package]] +name = "colored" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c" +dependencies = [ + "lazy_static", + "windows-sys 0.59.0", +] + +[[package]] +name = "combine" +version = "3.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da3da6baa321ec19e1cc41d31bf599f00c783d0517095cdaf0332e3fe8d20680" +dependencies = [ + "ascii", + "byteorder", + "either", + "memchr", + "unreachable", +] + +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "compression-codecs" +version = "0.4.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00828ba6fd27b45a448e57dbfe84f1029d4c9f26b368157e9a448a5f49a2ec2a" +dependencies = [ + "brotli", + "compression-core", + "flate2", + "memchr", +] + +[[package]] +name = "compression-core" +version = "0.4.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75984efb6ed102a0d42db99afb6c1948f0380d1d91808d5529916e6c08b49d8d" + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "console" +version = "0.15.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8" +dependencies = [ + "encode_unicode", + "libc", + "once_cell", + "unicode-width 0.2.2", + "windows-sys 0.59.0", +] + +[[package]] +name = "console" +version = "0.16.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03e45a4a8926227e4197636ba97a9fc9b00477e9f4bd711395687c5f0734bec4" +dependencies = [ + "encode_unicode", + "libc", + "once_cell", + "unicode-width 0.2.2", + "windows-sys 0.61.2", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "constant_time_eq" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b" + +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "typenum", +] + +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher", +] + +[[package]] +name = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest", + "fiat-crypto", + "rand_core 0.6.4", + "rustc_version", + "serde", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "darling" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" +dependencies = [ + "darling_core 0.13.4", + "darling_macro 0.13.4", +] + +[[package]] +name = "darling" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" +dependencies = [ + "darling_core 0.21.3", + "darling_macro 0.21.3", +] + +[[package]] +name = "darling_core" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim 0.10.0", + "syn 1.0.109", +] + +[[package]] +name = "darling_core" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim 0.11.1", + "syn 2.0.115", +] + +[[package]] +name = "darling_macro" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" +dependencies = [ + "darling_core 0.13.4", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "darling_macro" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" +dependencies = [ + "darling_core 0.21.3", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "dashmap" +version = "5.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +dependencies = [ + "cfg-if", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", +] + +[[package]] +name = "data-encoding" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea" + +[[package]] +name = "der" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "der-parser" +version = "8.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbd676fbbab537128ef0278adb5576cf363cff6aa22a7b24effe97347cfab61e" +dependencies = [ + "asn1-rs", + "displaydoc", + "nom", + "num-bigint 0.4.6", + "num-traits", + "rusticata-macros", +] + +[[package]] +name = "deranged" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc3dc5ad92c2e2d1c193bbbbdf2ea477cb81331de4f3103f267ca18368b988c4" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "derivation-path" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e5c37193a1db1d8ed868c03ec7b152175f26160a5b740e5e484143877e0adf0" + +[[package]] +name = "derive_more" +version = "0.99.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6edb4b64a43d977b8e99788fe3a04d483834fba1215a7e02caa415b626497f7f" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version", + "syn 2.0.115", +] + +[[package]] +name = "dialoguer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59c6f2989294b9a498d3ad5491a79c6deb604617378e1cdc4bfc1c1361fe2f87" +dependencies = [ + "console 0.15.11", + "shell-words", + "tempfile", + "zeroize", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[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.115", +] + +[[package]] +name = "dlopen2" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09b4f5f101177ff01b8ec4ecc81eead416a8aa42819a2869311b3420fa114ffa" +dependencies = [ + "dlopen2_derive", + "libc", + "once_cell", + "winapi", +] + +[[package]] +name = "dlopen2_derive" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cbae11b3de8fce2a456e8ea3dada226b35fe791f0dc1d360c0941f0bb681f3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "dptree" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d81175dab5ec79c30e0576df2ed2c244e1721720c302000bb321b107e82e265c" +dependencies = [ + "futures", +] + +[[package]] +name = "eager" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abe71d579d1812060163dff96056261deb5bf6729b100fa2e36a68b9649ba3d3" + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "pkcs8", + "signature", +] + +[[package]] +name = "ed25519-dalek" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9" +dependencies = [ + "curve25519-dalek", + "ed25519", + "rand_core 0.6.4", + "serde", + "sha2", + "subtle", + "zeroize", +] + +[[package]] +name = "ed25519-dalek-bip32" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b49a684b133c4980d7ee783936af771516011c8cd15f429dbda77245e282f03" +dependencies = [ + "derivation-path", + "ed25519-dalek", + "hmac", + "sha2", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest", + "ff", + "generic-array", + "group", + "pkcs8", + "rand_core 0.6.4", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "encode_unicode" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" + +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "enum-iterator" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fd242f399be1da0a5354aa462d57b4ab2b4ee0683cc552f7c007d2d12d36e94" +dependencies = [ + "enum-iterator-derive", +] + +[[package]] +name = "enum-iterator-derive" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "685adfa4d6f3d765a26bc5dbc936577de9abf756c1feeb3089b01dd395034842" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "erasable" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "437cfb75878119ed8265685c41a115724eae43fb7cc5a0bf0e4ecc3b803af1c4" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "event-listener" +version = "5.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" +dependencies = [ + "event-listener", + "pin-project-lite", +] + +[[package]] +name = "fastbloom" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7f34442dbe69c60fe8eaf58a8cafff81a1f278816d8ab4db255b3bef4ac3c4" +dependencies = [ + "getrandom 0.3.4", + "libm", + "rand 0.9.2", + "siphasher 1.0.2", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "feature-probe" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835a3dc7d1ec9e75e2b5fb4ba75396837112d2060b03f7d43bc1897c7f7211da" + +[[package]] +name = "fern" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9f0c14694cbd524c8720dd69b0e3179344f04ebb5f90f2e4a440c6ea3b2f1ee" +dependencies = [ + "colored 1.9.4", + "log", +] + +[[package]] +name = "ff" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" +dependencies = [ + "bitvec", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "five8" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23f76610e969fa1784327ded240f1e28a3fd9520c9cec93b636fcf62dd37f772" +dependencies = [ + "five8_core", +] + +[[package]] +name = "five8_const" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a0f1728185f277989ca573a402716ae0beaaea3f76a8ff87ef9dd8fb19436c5" +dependencies = [ + "five8_core", +] + +[[package]] +name = "five8_core" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "059c31d7d36c43fe39d89e55711858b4da8be7eb6dabac23c7289b1a19489406" + +[[package]] +name = "flate2" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futures" +version = "0.3.31" +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", +] + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-executor" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-macro" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "futures-sink" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-timer" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "gethostname" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1ebd34e35c46e00bb73e81363248d627782724609fe1b6396f553f68fe3862e" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "r-efi", + "wasip2", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139ef39800118c7683f2fd3c98c1b23c09ae076556b435f8e9064ae108aaeeec" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", + "wasip3", +] + +[[package]] +name = "glob" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" + +[[package]] +name = "governor" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68a7f542ee6b35af73b06abc0dad1c1bae89964e4e253bc4b587b91c9637867b" +dependencies = [ + "cfg-if", + "dashmap", + "futures", + "futures-timer", + "no-std-compat", + "nonzero_ext", + "parking_lot", + "portable-atomic", + "quanta", + "rand 0.8.5", + "smallvec", + "spinning_top", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand 0.8.5", + "rand_core 0.6.4", + "rand_xorshift", + "subtle", +] + +[[package]] +name = "h2" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0beca50380b1fc32983fc1cb4587bfa4bb9e78fc259aad4a0032d2080309222d" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http 0.2.12", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hash32" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" +dependencies = [ + "byteorder", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "hashbrown" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + +[[package]] +name = "histogram" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12cb882ccb290b8646e554b157ab0b71e64e8d5bef775cd66b6531e52d302669" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" +dependencies = [ + "bytes", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http 0.2.12", + "pin-project-lite", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http 1.4.0", +] + +[[package]] +name = "http-body-util" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" +dependencies = [ + "bytes", + "futures-core", + "http 1.4.0", + "http-body 1.0.1", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "humantime" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424" + +[[package]] +name = "hyper" +version = "0.14.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "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 = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" +dependencies = [ + "atomic-waker", + "bytes", + "futures-channel", + "futures-core", + "http 1.4.0", + "http-body 1.0.1", + "httparse", + "itoa", + "pin-project-lite", + "pin-utils", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +dependencies = [ + "futures-util", + "http 0.2.12", + "hyper 0.14.32", + "rustls 0.21.12", + "tokio", + "tokio-rustls 0.24.1", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" +dependencies = [ + "http 1.4.0", + "hyper 1.8.1", + "hyper-util", + "rustls 0.23.36", + "rustls-pki-types", + "tokio", + "tokio-rustls 0.26.4", + "tower-service", + "webpki-roots 1.0.6", +] + +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper 0.14.32", + "native-tls", + "tokio", + "tokio-native-tls", +] + +[[package]] +name = "hyper-util" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +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 = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "icu_collections" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" + +[[package]] +name = "icu_properties" +version = "2.1.2" +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", +] + +[[package]] +name = "icu_properties_data" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" + +[[package]] +name = "icu_provider" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +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 = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[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 = "indicatif" +version = "0.18.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9375e112e4b463ec1b1c6c011953545c65a30164fbab5b581df32b3abf0dcb88" +dependencies = [ + "console 0.16.2", + "portable-atomic", + "unicode-width 0.2.2", + "unit-prefix", + "web-time", +] + +[[package]] +name = "inout" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +dependencies = [ + "generic-array", +] + +[[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" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3640c1c38b8e4e43584d8df18be5fc6b0aa314ce6ebf51b53313d4306cca8e46" +dependencies = [ + "hermit-abi 0.5.2", + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "itertools" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +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 4.6.7", + "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 = "jsonrpc-core" +version = "18.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14f7f76aef2d054868398427f6c54943cf3d1caa9a7ec7d0c38d69df97a965eb" +dependencies = [ + "futures", + "futures-executor", + "futures-util", + "log", + "serde", + "serde_derive", + "serde_json", +] + +[[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", + "sha2", + "signature", +] + +[[package]] +name = "keccak" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb26cec98cce3a3d96cbb7bced3c4b16e3d13f27ec56dbd62cbc8f39cfb9d653" +dependencies = [ + "cpufeatures", +] + +[[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.182" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" + +[[package]] +name = "libfuzzer-sys" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f12a681b7dd8ce12bff52488013ba614b869148d54dd79836ab85aafdd53f08d" +dependencies = [ + "arbitrary", + "cc", +] + +[[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.11.0", + "libc", +] + +[[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-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "merlin" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58c38e2799fc0978b65dfff8023ec7843e2330bb462f19198840b34b6582397d" +dependencies = [ + "byteorder", + "keccak", + "rand_core 0.6.4", + "zeroize", +] + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "mime_guess" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e" +dependencies = [ + "mime", + "unicase", +] + +[[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", + "wasi", + "windows-sys 0.61.2", +] + +[[package]] +name = "native-tls" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d5d26952a508f321b4d3d2e80e78fc2603eaefcdf0c30783867f19586518bdc" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "never" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c96aba5aa877601bb3f6dd6a63a969e1f82e60646e81e71b14496995e9853c91" + +[[package]] +name = "nix" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" +dependencies = [ + "bitflags 2.11.0", + "cfg-if", + "cfg_aliases", + "libc", + "memoffset", +] + +[[package]] +name = "no-std-compat" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b93853da6d84c2e3c7d730d6473e8817692dd89be387eb01b94d7f108ecb5b8c" + +[[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 = "nonzero_ext" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38bf9645c8b145698bb0b18a4637dcacbc421ea49bef2317e4fd8065a387cf21" + +[[package]] +name = "num" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8536030f9fea7127f841b45bb6243b27255787fb4eb83958aa1ef9d2fdc0c36" +dependencies = [ + "num-bigint 0.2.6", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" +dependencies = [ + "autocfg", + "num-integer", + "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.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6b19411a9719e753aff12e5187b74d60d3dc449ec3f4dc21e3989c3f554bc95" +dependencies = [ + "autocfg", + "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-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[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.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef" +dependencies = [ + "autocfg", + "num-bigint 0.2.6", + "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", +] + +[[package]] +name = "num_cpus" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" +dependencies = [ + "hermit-abi 0.5.2", + "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 = "oid-registry" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bedf36ffb6ba96c2eb7144ef6270557b52e54b20c0a8e1eb2ff99a6c6959bff" +dependencies = [ + "asn1-rs", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "openssl" +version = "0.10.75" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328" +dependencies = [ + "bitflags 2.11.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.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" + +[[package]] +name = "openssl-sys" +version = "0.9.111" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "pairing" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fec4625e73cf41ef4bb6846cafa6d44736525f442ba45e407c4a000a13996f" +dependencies = [ + "group", +] + +[[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", + "smallvec", + "windows-link", +] + +[[package]] +name = "pastey" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b867cad97c0791bbd3aaa6472142568c6c9e8f71937e98379f584cfb0cf35bec" + +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest", +] + +[[package]] +name = "pbkdf2" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" +dependencies = [ + "digest", + "hmac", +] + +[[package]] +name = "pem" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8835c273a76a90455d7344889b0964598e3316e2a79ede8e36f16bdcf2228b8" +dependencies = [ + "base64 0.13.1", +] + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "percentage" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd23b938276f14057220b707937bcb42fa76dda7560e57a2da30cb52d557937" +dependencies = [ + "num", +] + +[[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 = "polyval" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" +dependencies = [ + "cfg-if", + "cpufeatures", + "opaque-debug", + "universal-hash", +] + +[[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 = "pretty-hex" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6fa0831dd7cc608c38a5e323422a0077678fa5744aa2be4ad91c4ece8eec8d5" + +[[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 = "proc-macro-crate" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" +dependencies = [ + "toml_edit 0.23.10+spec-1.0.0", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "qstring" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d464fae65fff2680baf48019211ce37aaec0c78e9264c84a3e484717f965104e" +dependencies = [ + "percent-encoding", +] + +[[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 = "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 2.1.1", + "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", + "fastbloom", + "getrandom 0.3.4", + "lru-slab", + "rand 0.9.2", + "ring", + "rustc-hash 2.1.1", + "rustls 0.23.36", + "rustls-pki-types", + "rustls-platform-verifier", + "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", +] + +[[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", +] + +[[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", +] + +[[package]] +name = "rand_xorshift" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +dependencies = [ + "rand_core 0.6.4", +] + +[[package]] +name = "raw-cpuid" +version = "11.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "498cd0dc59d73224351ee52a95fee0f1a617a2eae0e7d9d720cc622c73a54186" +dependencies = [ + "bitflags 2.11.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 = "rc-box" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897fecc9fac6febd4408f9e935e86df739b0023b625e610e0357535b9c8adad0" +dependencies = [ + "erasable", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags 2.11.0", +] + +[[package]] +name = "redox_users" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" +dependencies = [ + "getrandom 0.2.17", + "libredox", + "thiserror 1.0.69", +] + +[[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", +] + +[[package]] +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-syntax" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a96887878f22d7bad8a3b6dc5b7440e0ada9a245242924394987b21cf2210a4c" + +[[package]] +name = "reqwest" +version = "0.11.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" +dependencies = [ + "base64 0.21.7", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http 0.2.12", + "http-body 0.4.6", + "hyper 0.14.32", + "hyper-rustls 0.24.2", + "hyper-tls", + "ipnet", + "js-sys", + "log", + "mime", + "mime_guess", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls 0.21.12", + "rustls-pemfile", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper 0.1.2", + "system-configuration", + "tokio", + "tokio-native-tls", + "tokio-rustls 0.24.1", + "tokio-util", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams", + "web-sys", + "webpki-roots 0.25.4", + "winreg", +] + +[[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-channel", + "futures-core", + "futures-util", + "http 1.4.0", + "http-body 1.0.1", + "http-body-util", + "hyper 1.8.1", + "hyper-rustls 0.27.7", + "hyper-util", + "js-sys", + "log", + "percent-encoding", + "pin-project-lite", + "quinn", + "rustls 0.23.36", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper 1.0.2", + "tokio", + "tokio-rustls 0.26.4", + "tower", + "tower-http", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots 1.0.6", +] + +[[package]] +name = "reqwest-middleware" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57f17d28a6e6acfe1733fe24bcd30774d13bffa4b8a22535b4c8c98423088d4e" +dependencies = [ + "anyhow", + "async-trait", + "http 1.4.0", + "reqwest 0.12.28", + "serde", + "thiserror 1.0.69", + "tower-service", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.17", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rpassword" +version = "7.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66d4c8b64f049c6721ec8ccec37ddfc3d641c4a7fca57e8f2a89de509c73df39" +dependencies = [ + "libc", + "rtoolbox", + "windows-sys 0.59.0", +] + +[[package]] +name = "rtoolbox" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7cc970b249fbe527d6e02e0a227762c9108b2f49d81094fe357ffc6d14d7f6f" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rusticata-macros" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" +dependencies = [ + "nom", +] + +[[package]] +name = "rustix" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" +dependencies = [ + "bitflags 2.11.0", + "errno", + "libc", + "linux-raw-sys", + "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 = [ + "once_cell", + "ring", + "rustls-pki-types", + "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", + "rustls-pki-types", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64 0.21.7", +] + +[[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.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d99feebc72bae7ab76ba994bb5e121b8d83d910ca40b36e0921f53becc41784" +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", + "security-framework-sys", + "webpki-root-certs", + "windows-sys 0.61.2", +] + +[[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 = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "ryu" +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 = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "schannel" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" +dependencies = [ + "windows-sys 0.61.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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "security-framework" +version = "3.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d17b898a6d6948c3a8ee4372c17cb384f90d2e6e912ef00895b14fd7ab54ec38" +dependencies = [ + "bitflags 2.11.0", + "core-foundation 0.10.1", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "321c8673b092a9a42605034a9879d73cb79101ed5fd117bc9a597b89b4e9e61a" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde-big-array" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11fc7cc2c76d73e0f27ee52abbd64eec84d46f370c88371120433196934e4b7f" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_bytes" +version = "0.11.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5d440709e79d88e51ac01c4b72fc6cb7314017bb7da9eeff678aa94c10e3ea8" +dependencies = [ + "serde", + "serde_core", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_spanned" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_with" +version = "3.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fa237f2807440d238e0364a218270b98f767a00d3dada77b1c53ae88940e2e7" +dependencies = [ + "serde_core", + "serde_with_macros 3.16.1", +] + +[[package]] +name = "serde_with_macros" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082" +dependencies = [ + "darling 0.13.4", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "serde_with_macros" +version = "3.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52a8e3ca0ca629121f70ab50f95249e5a6f925cc0f6ffe8256c45b728875706c" +dependencies = [ + "darling 0.21.3", + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha2-const-stable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f179d4e11094a893b82fff208f74d448a7512f99f5a0acbd5c679b705f83ed9" + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest", + "keccak", +] + +[[package]] +name = "shell-words" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc6fe69c597f9c37bfeeeeeb33da3530379845f10be461a66d16d03eca2ded77" + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook-registry" +version = "1.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" +dependencies = [ + "errno", + "libc", +] + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core 0.6.4", +] + +[[package]] +name = "simd-adler32" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" + +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + +[[package]] +name = "siphasher" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e" + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "sniper" +version = "0.1.0" +dependencies = [ + "arrayref", + "base64 0.22.1", + "borsh", + "bs58", + "byteorder", + "chrono", + "colored 2.2.0", + "fern", + "futures", + "futures-util", + "log", + "reqwest 0.11.27", + "serde", + "serde_json", + "solana-account-decoder", + "solana-client", + "solana-commitment-config", + "solana-compute-budget-interface", + "solana-sdk", + "solana-system-interface 3.0.0", + "solana-transaction-status", + "spl-associated-token-account", + "spl-token", + "spl-token-client", + "teloxide", + "tokio", + "tokio-tungstenite 0.21.0", + "toml", + "trait-variant", +] + +[[package]] +name = "sniper-fuzz" +version = "0.0.0" +dependencies = [ + "libfuzzer-sys", + "sniper", +] + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0" +dependencies = [ + "libc", + "windows-sys 0.60.2", +] + +[[package]] +name = "solana-account" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efc0ed36decb689413b9da5d57f2be49eea5bebb3cf7897015167b0c4336e731" +dependencies = [ + "bincode", + "serde", + "serde_bytes", + "serde_derive", + "solana-account-info", + "solana-clock", + "solana-instruction-error", + "solana-pubkey 4.1.0", + "solana-sdk-ids", + "solana-sysvar", +] + +[[package]] +name = "solana-account-decoder" +version = "3.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66939b3e7aa0fab7a523bbb0d0518e3cdbb6a9b8675d5ae3a7bba5c1bef98622" +dependencies = [ + "Inflector", + "base64 0.22.1", + "bincode", + "bs58", + "bv", + "serde", + "serde_json", + "solana-account", + "solana-account-decoder-client-types", + "solana-address-lookup-table-interface", + "solana-clock", + "solana-config-interface", + "solana-epoch-schedule", + "solana-fee-calculator", + "solana-instruction", + "solana-loader-v3-interface", + "solana-nonce", + "solana-program-option", + "solana-program-pack", + "solana-pubkey 3.0.0", + "solana-rent", + "solana-sdk-ids", + "solana-slot-hashes", + "solana-slot-history", + "solana-stake-interface", + "solana-sysvar", + "solana-vote-interface", + "spl-generic-token", + "spl-token-2022-interface", + "spl-token-group-interface", + "spl-token-interface", + "spl-token-metadata-interface", + "thiserror 2.0.18", + "zstd", +] + +[[package]] +name = "solana-account-decoder-client-types" +version = "3.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bcf86e96f5e986687edc572033df43723b885c668fa1a3280753232dc8f3656" +dependencies = [ + "base64 0.22.1", + "bs58", + "serde", + "serde_json", + "solana-account", + "solana-pubkey 3.0.0", + "zstd", +] + +[[package]] +name = "solana-account-info" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc3397241392f5756925029acaa8515dc70fcbe3d8059d4885d7d6533baf64fd" +dependencies = [ + "bincode", + "serde_core", + "solana-address 2.2.0", + "solana-program-error", + "solana-program-memory", +] + +[[package]] +name = "solana-address" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2ecac8e1b7f74c2baa9e774c42817e3e75b20787134b76cc4d45e8a604488f5" +dependencies = [ + "solana-address 2.2.0", +] + +[[package]] +name = "solana-address" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68c5d02824391b072dc5cd0aaa85fb0af9784a21d23286a767994d1e8a322131" +dependencies = [ + "borsh", + "bytemuck", + "bytemuck_derive", + "curve25519-dalek", + "five8", + "five8_const", + "rand 0.9.2", + "serde", + "serde_derive", + "sha2-const-stable", + "solana-atomic-u64", + "solana-define-syscall 5.0.0", + "solana-program-error", + "solana-sanitize", + "solana-sha256-hasher", + "wincode", +] + +[[package]] +name = "solana-address-lookup-table-interface" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e8df0b083c10ce32490410f3795016b1b5d9b4d094658c0a5e496753645b7cd" +dependencies = [ + "bincode", + "bytemuck", + "serde", + "serde_derive", + "solana-clock", + "solana-instruction", + "solana-instruction-error", + "solana-pubkey 4.1.0", + "solana-sdk-ids", + "solana-slot-hashes", +] + +[[package]] +name = "solana-atomic-u64" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a933ff1e50aff72d02173cfcd7511bd8540b027ee720b75f353f594f834216d0" +dependencies = [ + "parking_lot", +] + +[[package]] +name = "solana-big-mod-exp" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30c80fb6d791b3925d5ec4bf23a7c169ef5090c013059ec3ed7d0b2c04efa085" +dependencies = [ + "num-bigint 0.4.6", + "num-traits", + "solana-define-syscall 3.0.0", +] + +[[package]] +name = "solana-bincode" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "278a1a5bad62cd9da89ac8d4b7ec444e83caa8ae96aa656dfc27684b28d49a5d" +dependencies = [ + "bincode", + "serde_core", + "solana-instruction-error", +] + +[[package]] +name = "solana-blake3-hasher" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7116e1d942a2432ca3f514625104757ab8a56233787e95144c93950029e31176" +dependencies = [ + "blake3", + "solana-define-syscall 4.0.1", + "solana-hash 4.2.0", +] + +[[package]] +name = "solana-bls-signatures" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c75573697bbb148afa8209aa3ce228ca0754584c9a8a91e818db0f706ae4fb" +dependencies = [ + "base64 0.22.1", + "blst", + "blstrs", + "cfg_eval", + "ff", + "group", + "pairing", + "rand 0.8.5", + "serde", + "serde_json", + "serde_with", + "thiserror 2.0.18", +] + +[[package]] +name = "solana-borsh" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc402b16657abbfa9991cd5cbfac5a11d809f7e7d28d3bb291baeb088b39060e" +dependencies = [ + "borsh", +] + +[[package]] +name = "solana-clap-utils" +version = "3.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1a2875a1d148c9f356c4dc237681cb66b504cbe431ca468f1ec587173a3d416" +dependencies = [ + "chrono", + "clap", + "rpassword", + "solana-bls-signatures", + "solana-clock", + "solana-cluster-type", + "solana-commitment-config", + "solana-derivation-path", + "solana-hash 3.1.0", + "solana-keypair", + "solana-message", + "solana-native-token", + "solana-presigner", + "solana-pubkey 3.0.0", + "solana-remote-wallet", + "solana-seed-phrase", + "solana-signature", + "solana-signer", + "thiserror 2.0.18", + "tiny-bip39", + "uriparse", + "url", +] + +[[package]] +name = "solana-cli-config" +version = "3.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70215cf542074daf7d2c60241f018574fdc01add7af8c57254a84fd40525fc82" +dependencies = [ + "dirs-next", + "serde", + "serde_yaml", + "solana-clap-utils", + "solana-commitment-config", + "url", +] + +[[package]] +name = "solana-cli-output" +version = "3.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c75b9c6f7b0ab8617eb03b22c78b860af588f6f1bc76c5ada6b8125a9826b4c8" +dependencies = [ + "Inflector", + "agave-reserved-account-keys", + "base64 0.22.1", + "chrono", + "clap", + "console 0.16.2", + "humantime", + "indicatif", + "pretty-hex", + "semver", + "serde", + "serde_json", + "solana-account", + "solana-account-decoder", + "solana-bincode", + "solana-clap-utils", + "solana-cli-config", + "solana-clock", + "solana-epoch-info", + "solana-hash 3.1.0", + "solana-message", + "solana-packet", + "solana-pubkey 3.0.0", + "solana-rpc-client-api", + "solana-sdk-ids", + "solana-signature", + "solana-stake-interface", + "solana-system-interface 2.0.0", + "solana-transaction", + "solana-transaction-error", + "solana-transaction-status", + "solana-transaction-status-client-types", + "solana-vote-program", + "spl-memo-interface", +] + +[[package]] +name = "solana-client" +version = "3.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "061e7290051a639e0efe8078b6c8c7ebe99d13f56ee651b93c0529fba012b99d" +dependencies = [ + "async-trait", + "bincode", + "dashmap", + "futures", + "futures-util", + "indexmap", + "indicatif", + "log", + "quinn", + "rayon", + "solana-account", + "solana-client-traits", + "solana-commitment-config", + "solana-connection-cache", + "solana-epoch-info", + "solana-hash 3.1.0", + "solana-instruction", + "solana-keypair", + "solana-measure", + "solana-message", + "solana-net-utils", + "solana-pubkey 3.0.0", + "solana-pubsub-client", + "solana-quic-client", + "solana-quic-definitions", + "solana-rpc-client", + "solana-rpc-client-api", + "solana-rpc-client-nonce-utils", + "solana-signature", + "solana-signer", + "solana-streamer", + "solana-time-utils", + "solana-tpu-client", + "solana-transaction", + "solana-transaction-error", + "solana-transaction-status-client-types", + "solana-udp-client", + "thiserror 2.0.18", + "tokio", + "tokio-util", +] + +[[package]] +name = "solana-client-traits" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08618ed587e128105510c54ae3e456b9a06d674d8640db75afe66dad65cb4e02" +dependencies = [ + "solana-account", + "solana-commitment-config", + "solana-epoch-info", + "solana-hash 3.1.0", + "solana-instruction", + "solana-keypair", + "solana-message", + "solana-pubkey 3.0.0", + "solana-signature", + "solana-signer", + "solana-system-interface 2.0.0", + "solana-transaction", + "solana-transaction-error", +] + +[[package]] +name = "solana-clock" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb62e9381182459a4520b5fe7fb22d423cae736239a6427fc398a88743d0ed59" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-sysvar-id", +] + +[[package]] +name = "solana-cluster-type" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb7692fa6bf10a1a86b450c4775526f56d7e0e2116a53313f2533b5694abea64" +dependencies = [ + "solana-hash 3.1.0", +] + +[[package]] +name = "solana-commitment-config" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e41a3917076a8b5375809078ae3a6fb76a53e364b596ef8c4265e7f410876f3" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "solana-compute-budget-interface" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8292c436b269ad23cecc8b24f7da3ab07ca111661e25e00ce0e1d22771951ab9" +dependencies = [ + "solana-instruction", + "solana-sdk-ids", +] + +[[package]] +name = "solana-config-interface" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e401ae56aed512821cc7a0adaa412ff97fecd2dff4602be7b1330d2daec0c4" +dependencies = [ + "bincode", + "serde", + "serde_derive", + "solana-account", + "solana-instruction", + "solana-pubkey 3.0.0", + "solana-sdk-ids", + "solana-short-vec", + "solana-system-interface 2.0.0", +] + +[[package]] +name = "solana-connection-cache" +version = "3.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0cf8656543f9c391b1fd06397038c1586162cbd4630274580cfc0993388b3ae" +dependencies = [ + "async-trait", + "bincode", + "crossbeam-channel", + "futures-util", + "indexmap", + "log", + "rand 0.8.5", + "rayon", + "solana-keypair", + "solana-measure", + "solana-metrics", + "solana-time-utils", + "solana-transaction-error", + "thiserror 2.0.18", + "tokio", +] + +[[package]] +name = "solana-cpi" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dea26709d867aada85d0d3617db0944215c8bb28d3745b912de7db13a23280c" +dependencies = [ + "solana-account-info", + "solana-define-syscall 4.0.1", + "solana-instruction", + "solana-program-error", + "solana-pubkey 4.1.0", + "solana-stable-layout", +] + +[[package]] +name = "solana-curve25519" +version = "3.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "737ede9143c36b8628cc11d920cdb762cd1ccbd7ca904c3bd63b39c58669fe38" +dependencies = [ + "bytemuck", + "bytemuck_derive", + "curve25519-dalek", + "solana-define-syscall 3.0.0", + "subtle", + "thiserror 2.0.18", +] + +[[package]] +name = "solana-define-syscall" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9697086a4e102d28a156b8d6b521730335d6951bd39a5e766512bbe09007cee" + +[[package]] +name = "solana-define-syscall" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57e5b1c0bc1d4a4d10c88a4100499d954c09d3fecfae4912c1a074dff68b1738" + +[[package]] +name = "solana-define-syscall" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03aacdd7a61e2109887a7a7f046caebafce97ddf1150f33722eeac04f9039c73" + +[[package]] +name = "solana-derivation-path" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff71743072690fdbdfcdc37700ae1cb77485aaad49019473a81aee099b1e0b8c" +dependencies = [ + "derivation-path", + "qstring", + "uriparse", +] + +[[package]] +name = "solana-epoch-info" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e093c84f6ece620a6b10cd036574b0cd51944231ab32d81f80f76d54aba833e6" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "solana-epoch-rewards" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b319a4ed70390af911090c020571f0ff1f4ec432522d05ab89f5c08080381995" +dependencies = [ + "serde", + "serde_derive", + "solana-hash 3.1.0", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-sysvar-id", +] + +[[package]] +name = "solana-epoch-rewards-hasher" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ee8beac9bff4db9225e57d532d169b0be5e447f1e6601a2f50f27a01bf5518f" +dependencies = [ + "siphasher 0.3.11", + "solana-address 2.2.0", + "solana-hash 4.2.0", +] + +[[package]] +name = "solana-epoch-schedule" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e5481e72cc4d52c169db73e4c0cd16de8bc943078aac587ec4817a75cc6388f" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-sysvar-id", +] + +[[package]] +name = "solana-epoch-stake" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc6693d0ea833b880514b9b88d95afb80b42762dca98b0712465d1fcbbcb89e" +dependencies = [ + "solana-define-syscall 3.0.0", + "solana-pubkey 3.0.0", +] + +[[package]] +name = "solana-example-mocks" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978855d164845c1b0235d4b4d101cadc55373fffaf0b5b6cfa2194d25b2ed658" +dependencies = [ + "serde", + "serde_derive", + "solana-address-lookup-table-interface", + "solana-clock", + "solana-hash 3.1.0", + "solana-instruction", + "solana-keccak-hasher", + "solana-message", + "solana-nonce", + "solana-pubkey 3.0.0", + "solana-sdk-ids", + "solana-system-interface 2.0.0", + "thiserror 2.0.18", +] + +[[package]] +name = "solana-feature-gate-interface" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75ca9b5cbb6f500f7fd73db5bd95640f71a83f04d6121a0e59a43b202dca2731" +dependencies = [ + "serde", + "serde_derive", + "solana-program-error", + "solana-pubkey 4.1.0", + "solana-sdk-ids", +] + +[[package]] +name = "solana-fee-calculator" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b2a5675b2cf8d407c672dc1776492b1f382337720ddf566645ae43237a3d8c3" +dependencies = [ + "log", + "serde", + "serde_derive", +] + +[[package]] +name = "solana-fee-structure" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e2abdb1223eea8ec64136f39cb1ffcf257e00f915c957c35c0dd9e3f4e700b0" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "solana-hard-forks" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0abacc4b66ce471f135f48f22facf75cbbb0f8a252fbe2c1e0aa59d5b203f519" + +[[package]] +name = "solana-hash" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "337c246447142f660f778cf6cb582beba8e28deb05b3b24bfb9ffd7c562e5f41" +dependencies = [ + "solana-hash 4.2.0", +] + +[[package]] +name = "solana-hash" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8064ea1d591ec791be95245058ca40f4f5345d390c200069d0f79bbf55bfae55" +dependencies = [ + "borsh", + "bytemuck", + "bytemuck_derive", + "five8", + "serde", + "serde_derive", + "solana-atomic-u64", + "solana-sanitize", + "wincode", +] + +[[package]] +name = "solana-inflation" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e92f37a14e7c660628752833250dd3dcd8e95309876aee751d7f8769a27947c6" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "solana-instruction" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee1b699a2c1518028a9982e255e0eca10c44d90006542d9d7f9f40dbce3f7c78" +dependencies = [ + "bincode", + "borsh", + "serde", + "serde_derive", + "solana-define-syscall 4.0.1", + "solana-instruction-error", + "solana-pubkey 4.1.0", +] + +[[package]] +name = "solana-instruction-error" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b04259e03c05faf38a8c24217b5cfe4c90572ae6184ab49cddb1584fdd756d3f" +dependencies = [ + "num-traits", + "serde", + "serde_derive", + "solana-program-error", +] + +[[package]] +name = "solana-instructions-sysvar" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ddf67876c541aa1e21ee1acae35c95c6fbc61119814bfef70579317a5e26955" +dependencies = [ + "bitflags 2.11.0", + "solana-account-info", + "solana-instruction", + "solana-instruction-error", + "solana-program-error", + "solana-pubkey 3.0.0", + "solana-sanitize", + "solana-sdk-ids", + "solana-serialize-utils", + "solana-sysvar-id", +] + +[[package]] +name = "solana-keccak-hasher" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed1c0d16d6fdeba12291a1f068cdf0d479d9bff1141bf44afd7aa9d485f65ef8" +dependencies = [ + "sha3", + "solana-define-syscall 4.0.1", + "solana-hash 4.2.0", +] + +[[package]] +name = "solana-keypair" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ac8be597c9e231b0cab2928ce3bc3e4ee77d9c0ad92977b9d901f3879f25a7a" +dependencies = [ + "ed25519-dalek", + "ed25519-dalek-bip32", + "five8", + "rand 0.8.5", + "solana-address 2.2.0", + "solana-derivation-path", + "solana-seed-derivable", + "solana-seed-phrase", + "solana-signature", + "solana-signer", +] + +[[package]] +name = "solana-last-restart-slot" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcda154ec827f5fc1e4da0af3417951b7e9b8157540f81f936c4a8b1156134d0" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-sysvar-id", +] + +[[package]] +name = "solana-loader-v2-interface" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e4a6f0ad4fd9c30679bfee2ce3ea6a449cac38049f210480b751f65676dfe82" +dependencies = [ + "serde", + "serde_bytes", + "serde_derive", + "solana-instruction", + "solana-pubkey 3.0.0", + "solana-sdk-ids", +] + +[[package]] +name = "solana-loader-v3-interface" +version = "6.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dee44c9b1328c5c712c68966fb8de07b47f3e7bac006e74ddd1bb053d3e46e5d" +dependencies = [ + "serde", + "serde_bytes", + "serde_derive", + "solana-instruction", + "solana-pubkey 3.0.0", + "solana-sdk-ids", + "solana-system-interface 2.0.0", +] + +[[package]] +name = "solana-measure" +version = "3.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be8c8288f2b0755aaec2bae772239a48408e076a9b90db40c936f1fa5debbc78" + +[[package]] +name = "solana-message" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0448b1fd891c5f46491e5dc7d9986385ba3c852c340db2911dd29faa01d2b08d" +dependencies = [ + "bincode", + "blake3", + "lazy_static", + "serde", + "serde_derive", + "solana-address 2.2.0", + "solana-hash 4.2.0", + "solana-instruction", + "solana-sanitize", + "solana-sdk-ids", + "solana-short-vec", + "solana-transaction-error", +] + +[[package]] +name = "solana-metrics" +version = "3.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dac53c2ae91e227cd1f0aa9f744beca638a2e971b84d7c2f008cf2c75af1b0d5" +dependencies = [ + "crossbeam-channel", + "gethostname", + "log", + "reqwest 0.12.28", + "solana-cluster-type", + "solana-sha256-hasher", + "solana-time-utils", + "thiserror 2.0.18", +] + +[[package]] +name = "solana-msg" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "264275c556ea7e22b9d3f87d56305546a38d4eee8ec884f3b126236cb7dcbbb4" +dependencies = [ + "solana-define-syscall 3.0.0", +] + +[[package]] +name = "solana-native-token" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae8dd4c280dca9d046139eb5b7a5ac9ad10403fbd64964c7d7571214950d758f" + +[[package]] +name = "solana-net-utils" +version = "3.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23848218da169349b400780ee5d8d683792304115d4b675f0d9e0b8949433eb2" +dependencies = [ + "anyhow", + "bincode", + "bytes", + "cfg-if", + "dashmap", + "itertools 0.12.1", + "log", + "nix", + "rand 0.8.5", + "serde", + "socket2 0.6.2", + "solana-serde", + "solana-svm-type-overrides", + "tokio", + "url", +] + +[[package]] +name = "solana-nonce" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbc469152a63284ef959b80c59cda015262a021da55d3b8fe42171d89c4b64f8" +dependencies = [ + "serde", + "serde_derive", + "solana-fee-calculator", + "solana-hash 4.2.0", + "solana-pubkey 4.1.0", + "solana-sha256-hasher", +] + +[[package]] +name = "solana-offchain-message" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6e2a1141a673f72a05cf406b99e4b2b8a457792b7c01afa07b3f00d4e2de393" +dependencies = [ + "num_enum", + "solana-hash 3.1.0", + "solana-packet", + "solana-pubkey 3.0.0", + "solana-sanitize", + "solana-sha256-hasher", + "solana-signature", + "solana-signer", +] + +[[package]] +name = "solana-packet" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6edf2f25743c95229ac0fdc32f8f5893ef738dbf332c669e9861d33ddb0f469d" +dependencies = [ + "bincode", + "bitflags 2.11.0", + "cfg_eval", + "serde", + "serde_derive", + "serde_with", +] + +[[package]] +name = "solana-perf" +version = "3.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87608537c53ca0976f04166691fc11523e93802a50660b719e62e172dd47cf10" +dependencies = [ + "ahash", + "bincode", + "bv", + "bytes", + "caps", + "curve25519-dalek", + "dlopen2", + "fnv", + "libc", + "log", + "nix", + "rand 0.8.5", + "rayon", + "serde", + "solana-hash 3.1.0", + "solana-message", + "solana-metrics", + "solana-packet", + "solana-pubkey 3.0.0", + "solana-rayon-threadlimit", + "solana-sdk-ids", + "solana-short-vec", + "solana-signature", + "solana-time-utils", + "solana-transaction-context", +] + +[[package]] +name = "solana-precompile-error" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cafcd950de74c6c39d55dc8ca108bbb007799842ab370ef26cf45a34453c31e1" +dependencies = [ + "num-traits", +] + +[[package]] +name = "solana-presigner" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f704eaf825be3180832445b9e4983b875340696e8e7239bf2d535b0f86c14a2" +dependencies = [ + "solana-pubkey 3.0.0", + "solana-signature", + "solana-signer", +] + +[[package]] +name = "solana-program" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91b12305dd81045d705f427acd0435a2e46444b65367d7179d7bdcfc3bc5f5eb" +dependencies = [ + "memoffset", + "solana-account-info", + "solana-big-mod-exp", + "solana-blake3-hasher", + "solana-borsh", + "solana-clock", + "solana-cpi", + "solana-define-syscall 3.0.0", + "solana-epoch-rewards", + "solana-epoch-schedule", + "solana-epoch-stake", + "solana-example-mocks", + "solana-fee-calculator", + "solana-hash 3.1.0", + "solana-instruction", + "solana-instruction-error", + "solana-instructions-sysvar", + "solana-keccak-hasher", + "solana-last-restart-slot", + "solana-msg", + "solana-native-token", + "solana-program-entrypoint", + "solana-program-error", + "solana-program-memory", + "solana-program-option", + "solana-program-pack", + "solana-pubkey 3.0.0", + "solana-rent", + "solana-sdk-ids", + "solana-secp256k1-recover", + "solana-serde-varint", + "solana-serialize-utils", + "solana-sha256-hasher", + "solana-short-vec", + "solana-slot-hashes", + "solana-slot-history", + "solana-stable-layout", + "solana-sysvar", + "solana-sysvar-id", +] + +[[package]] +name = "solana-program-entrypoint" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84c9b0a1ff494e05f503a08b3d51150b73aa639544631e510279d6375f290997" +dependencies = [ + "solana-account-info", + "solana-define-syscall 4.0.1", + "solana-program-error", + "solana-pubkey 4.1.0", +] + +[[package]] +name = "solana-program-error" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1af32c995a7b692a915bb7414d5f8e838450cf7c70414e763d8abcae7b51f28" +dependencies = [ + "borsh", + "serde", + "serde_derive", +] + +[[package]] +name = "solana-program-memory" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4068648649653c2c50546e9a7fb761791b5ab0cda054c771bb5808d3a4b9eb52" +dependencies = [ + "solana-define-syscall 4.0.1", +] + +[[package]] +name = "solana-program-option" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e7b4ddb464f274deb4a497712664c3b612e3f5f82471d4e47710fc4ab1c3095" + +[[package]] +name = "solana-program-pack" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c169359de21f6034a63ebf96d6b380980307df17a8d371344ff04a883ec4e9d0" +dependencies = [ + "solana-program-error", +] + +[[package]] +name = "solana-program-runtime" +version = "3.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a03ee54e20e5562f347121517c1692489a6a8e04f86aefd5740af5097c33820" +dependencies = [ + "base64 0.22.1", + "bincode", + "itertools 0.12.1", + "log", + "percentage", + "rand 0.8.5", + "serde", + "solana-account", + "solana-account-info", + "solana-clock", + "solana-epoch-rewards", + "solana-epoch-schedule", + "solana-fee-structure", + "solana-hash 3.1.0", + "solana-instruction", + "solana-last-restart-slot", + "solana-loader-v3-interface", + "solana-program-entrypoint", + "solana-pubkey 3.0.0", + "solana-rent", + "solana-sbpf", + "solana-sdk-ids", + "solana-slot-hashes", + "solana-stable-layout", + "solana-stake-interface", + "solana-svm-callback", + "solana-svm-feature-set", + "solana-svm-log-collector", + "solana-svm-measure", + "solana-svm-timings", + "solana-svm-transaction", + "solana-svm-type-overrides", + "solana-system-interface 2.0.0", + "solana-sysvar", + "solana-sysvar-id", + "solana-transaction-context", + "thiserror 2.0.18", +] + +[[package]] +name = "solana-pubkey" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8909d399deb0851aa524420beeb5646b115fd253ef446e35fe4504c904da3941" +dependencies = [ + "rand 0.8.5", + "solana-address 1.1.0", +] + +[[package]] +name = "solana-pubkey" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b06bd918d60111ee1f97de817113e2040ca0cedb740099ee8d646233f6b906c" +dependencies = [ + "solana-address 2.2.0", +] + +[[package]] +name = "solana-pubsub-client" +version = "3.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1305d955b8da57ec22b0410630df61770fbae6b8e93aa91bb0fb76f01bc56f8a" +dependencies = [ + "crossbeam-channel", + "futures-util", + "http 0.2.12", + "log", + "semver", + "serde", + "serde_json", + "solana-account-decoder-client-types", + "solana-clock", + "solana-pubkey 3.0.0", + "solana-rpc-client-types", + "solana-signature", + "thiserror 2.0.18", + "tokio", + "tokio-stream", + "tokio-tungstenite 0.28.0", + "tungstenite 0.28.0", + "url", +] + +[[package]] +name = "solana-quic-client" +version = "3.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e472c50da5a07aec4253857a507edfcdd3c0a03d0012f213776ccf18de0aafe0" +dependencies = [ + "async-lock", + "async-trait", + "futures", + "itertools 0.12.1", + "log", + "quinn", + "quinn-proto", + "rustls 0.23.36", + "solana-connection-cache", + "solana-keypair", + "solana-measure", + "solana-metrics", + "solana-net-utils", + "solana-pubkey 3.0.0", + "solana-quic-definitions", + "solana-rpc-client-api", + "solana-signer", + "solana-streamer", + "solana-tls-utils", + "solana-transaction-error", + "thiserror 2.0.18", + "tokio", +] + +[[package]] +name = "solana-quic-definitions" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15319accf7d3afd845817aeffa6edd8cc185f135cefbc6b985df29cfd8c09609" +dependencies = [ + "solana-keypair", +] + +[[package]] +name = "solana-rayon-threadlimit" +version = "3.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbd391cd6ef3d8a3da4a6981a38050ac1449d8472bcbd394fbe1e35fc039424c" +dependencies = [ + "log", + "num_cpus", +] + +[[package]] +name = "solana-remote-wallet" +version = "3.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f9cd2c9bd26e6f1faaa45a5d24403f85816651c31e5eb2e06a1749e129fd4e8" +dependencies = [ + "console 0.16.2", + "dialoguer", + "log", + "num-derive", + "num-traits", + "parking_lot", + "qstring", + "semver", + "solana-derivation-path", + "solana-offchain-message", + "solana-pubkey 3.0.0", + "solana-signature", + "solana-signer", + "thiserror 2.0.18", + "uriparse", +] + +[[package]] +name = "solana-rent" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e860d5499a705369778647e97d760f7670adfb6fc8419dd3d568deccd46d5487" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-sysvar-id", +] + +[[package]] +name = "solana-reward-info" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82be7946105c2ee6be9f9ee7bd18a068b558389221d29efa92b906476102bfcc" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "solana-rpc-client" +version = "3.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7476104ef972be862a9c4989bb0d5798971a022a23becbd874f854733500d0a6" +dependencies = [ + "async-trait", + "base64 0.22.1", + "bincode", + "bs58", + "futures", + "indicatif", + "log", + "reqwest 0.12.28", + "reqwest-middleware", + "semver", + "serde", + "serde_json", + "solana-account", + "solana-account-decoder", + "solana-account-decoder-client-types", + "solana-clock", + "solana-commitment-config", + "solana-epoch-info", + "solana-epoch-schedule", + "solana-feature-gate-interface", + "solana-hash 3.1.0", + "solana-instruction", + "solana-message", + "solana-pubkey 3.0.0", + "solana-rpc-client-api", + "solana-signature", + "solana-transaction", + "solana-transaction-error", + "solana-transaction-status-client-types", + "solana-version", + "solana-vote-interface", + "tokio", +] + +[[package]] +name = "solana-rpc-client-api" +version = "3.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f139578f2184aa2299d36dc2da71233d695fbbe7925fed5649bf614f96783383" +dependencies = [ + "anyhow", + "jsonrpc-core", + "reqwest 0.12.28", + "reqwest-middleware", + "serde", + "serde_json", + "solana-account-decoder-client-types", + "solana-clock", + "solana-rpc-client-types", + "solana-signer", + "solana-transaction-error", + "solana-transaction-status-client-types", + "thiserror 2.0.18", +] + +[[package]] +name = "solana-rpc-client-nonce-utils" +version = "3.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28bd892ee8c80db85bf78594dde4dd2537ba11d419bf30676e7ab948da290675" +dependencies = [ + "solana-account", + "solana-commitment-config", + "solana-hash 3.1.0", + "solana-message", + "solana-nonce", + "solana-pubkey 3.0.0", + "solana-rpc-client", + "solana-sdk-ids", + "thiserror 2.0.18", +] + +[[package]] +name = "solana-rpc-client-types" +version = "3.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "104f40726fc48ad80b6b52ba7f3300a6ea2a87307cd5560afe943027d95e2b56" +dependencies = [ + "base64 0.22.1", + "bs58", + "semver", + "serde", + "serde_json", + "solana-account", + "solana-account-decoder-client-types", + "solana-address 1.1.0", + "solana-clock", + "solana-commitment-config", + "solana-fee-calculator", + "solana-inflation", + "solana-reward-info", + "solana-transaction", + "solana-transaction-error", + "solana-transaction-status-client-types", + "solana-version", + "spl-generic-token", + "thiserror 2.0.18", +] + +[[package]] +name = "solana-sanitize" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf09694a0fc14e5ffb18f9b7b7c0f15ecb6eac5b5610bf76a1853459d19daf9" + +[[package]] +name = "solana-sbpf" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15b079e08471a9dbfe1e48b2c7439c85aa2a055cbd54eddd8bd257b0a7dbb29" +dependencies = [ + "byteorder", + "combine 3.8.1", + "hash32", + "libc", + "log", + "rand 0.8.5", + "rustc-demangle", + "thiserror 2.0.18", + "winapi", +] + +[[package]] +name = "solana-sdk" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f03df7969f5e723ad31b6c9eadccc209037ac4caa34d8dc259316b05c11e82b" +dependencies = [ + "bincode", + "bs58", + "serde", + "solana-account", + "solana-epoch-info", + "solana-epoch-rewards-hasher", + "solana-fee-structure", + "solana-inflation", + "solana-keypair", + "solana-message", + "solana-offchain-message", + "solana-presigner", + "solana-program", + "solana-program-memory", + "solana-pubkey 3.0.0", + "solana-sanitize", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-seed-derivable", + "solana-seed-phrase", + "solana-serde", + "solana-serde-varint", + "solana-short-vec", + "solana-shred-version", + "solana-signature", + "solana-signer", + "solana-time-utils", + "solana-transaction", + "solana-transaction-error", + "thiserror 2.0.18", +] + +[[package]] +name = "solana-sdk-ids" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "def234c1956ff616d46c9dd953f251fa7096ddbaa6d52b165218de97882b7280" +dependencies = [ + "solana-address 2.2.0", +] + +[[package]] +name = "solana-sdk-macro" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6430000e97083460b71d9fbadc52a2ab2f88f53b3a4c5e58c5ae3640a0e8c00" +dependencies = [ + "bs58", + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "solana-secp256k1-recover" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9de18cfdab99eeb940fbedd8c981fa130c0d76252da75d05446f22fae8b51932" +dependencies = [ + "k256", + "solana-define-syscall 4.0.1", + "thiserror 2.0.18", +] + +[[package]] +name = "solana-security-txt" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "156bb61a96c605fa124e052d630dba2f6fb57e08c7d15b757e1e958b3ed7b3fe" +dependencies = [ + "hashbrown 0.15.2", +] + +[[package]] +name = "solana-seed-derivable" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff7bdb72758e3bec33ed0e2658a920f1f35dfb9ed576b951d20d63cb61ecd95c" +dependencies = [ + "solana-derivation-path", +] + +[[package]] +name = "solana-seed-phrase" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc905b200a95f2ea9146e43f2a7181e3aeb55de6bc12afb36462d00a3c7310de" +dependencies = [ + "hmac", + "pbkdf2 0.11.0", + "sha2", +] + +[[package]] +name = "solana-serde" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "709a93cab694c70f40b279d497639788fc2ccbcf9b4aa32273d4b361322c02dd" +dependencies = [ + "serde", +] + +[[package]] +name = "solana-serde-varint" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e5174c57d5ff3c1995f274d17156964664566e2cde18a07bba1586d35a70d3b" +dependencies = [ + "serde", +] + +[[package]] +name = "solana-serialize-utils" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e41dd8feea239516c623a02f0a81c2367f4b604d7965237fed0751aeec33ed" +dependencies = [ + "solana-instruction-error", + "solana-pubkey 3.0.0", + "solana-sanitize", +] + +[[package]] +name = "solana-sha256-hasher" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db7dc3011ea4c0334aaaa7e7128cb390ecf546b28d412e9bf2064680f57f588f" +dependencies = [ + "sha2", + "solana-define-syscall 4.0.1", + "solana-hash 4.2.0", +] + +[[package]] +name = "solana-short-vec" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3bd991c2cc415291c86bb0b6b4d53e93d13bb40344e4c5a2884e0e4f5fa93f" +dependencies = [ + "serde_core", +] + +[[package]] +name = "solana-shred-version" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94953e22ca28fe4541a3447d6baeaf519cc4ddc063253bfa673b721f34c136bb" +dependencies = [ + "solana-hard-forks", + "solana-hash 3.1.0", + "solana-sha256-hasher", +] + +[[package]] +name = "solana-signature" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "132a93134f1262aa832f1849b83bec6c9945669b866da18661a427943b9e801e" +dependencies = [ + "ed25519-dalek", + "five8", + "rand 0.9.2", + "serde", + "serde-big-array", + "serde_derive", + "solana-sanitize", + "wincode", +] + +[[package]] +name = "solana-signer" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bfea97951fee8bae0d6038f39a5efcb6230ecdfe33425ac75196d1a1e3e3235" +dependencies = [ + "solana-pubkey 3.0.0", + "solana-signature", + "solana-transaction-error", +] + +[[package]] +name = "solana-slot-hashes" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80a293f952293281443c04f4d96afd9d547721923d596e92b4377ed2360f1746" +dependencies = [ + "serde", + "serde_derive", + "solana-hash 3.1.0", + "solana-sdk-ids", + "solana-sysvar-id", +] + +[[package]] +name = "solana-slot-history" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f914f6b108f5bba14a280b458d023e3621c9973f27f015a4d755b50e88d89e97" +dependencies = [ + "bv", + "serde", + "serde_derive", + "solana-sdk-ids", + "solana-sysvar-id", +] + +[[package]] +name = "solana-stable-layout" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1da74507795b6e8fb60b7c7306c0c36e2c315805d16eaaf479452661234685ac" +dependencies = [ + "solana-instruction", + "solana-pubkey 3.0.0", +] + +[[package]] +name = "solana-stake-interface" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9bc26191b533f9a6e5a14cca05174119819ced680a80febff2f5051a713f0db" +dependencies = [ + "num-traits", + "serde", + "serde_derive", + "solana-clock", + "solana-cpi", + "solana-instruction", + "solana-program-error", + "solana-pubkey 3.0.0", + "solana-system-interface 2.0.0", + "solana-sysvar", + "solana-sysvar-id", +] + +[[package]] +name = "solana-streamer" +version = "3.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f71881ba229a4dbdc1790ad6d367f40dd42b4eea0e8ef1076d867c27424d5d4c" +dependencies = [ + "arc-swap", + "bytes", + "crossbeam-channel", + "dashmap", + "futures", + "futures-util", + "governor", + "histogram", + "indexmap", + "itertools 0.12.1", + "libc", + "log", + "nix", + "num_cpus", + "pem", + "percentage", + "quinn", + "quinn-proto", + "rand 0.8.5", + "rustls 0.23.36", + "smallvec", + "socket2 0.6.2", + "solana-keypair", + "solana-measure", + "solana-metrics", + "solana-net-utils", + "solana-packet", + "solana-perf", + "solana-pubkey 3.0.0", + "solana-quic-definitions", + "solana-signature", + "solana-signer", + "solana-time-utils", + "solana-tls-utils", + "solana-transaction-error", + "solana-transaction-metrics-tracker", + "thiserror 2.0.18", + "tokio", + "tokio-util", + "x509-parser", +] + +[[package]] +name = "solana-svm-callback" +version = "3.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c216afeef20cf86fd3d2ae812bebcdc23ee0e3d45fb4b3b28ad168cb56778ed" +dependencies = [ + "solana-account", + "solana-clock", + "solana-precompile-error", + "solana-pubkey 3.0.0", +] + +[[package]] +name = "solana-svm-feature-set" +version = "3.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "641cddc667abba4cf3474d850a073c0a2b439ff0014c445cd09eaf5d79d70bab" + +[[package]] +name = "solana-svm-log-collector" +version = "3.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbe6ce42b1620fd713e12cd52d62a7d4d370414d67ed9bfc5faa444fa54bb6f2" +dependencies = [ + "log", +] + +[[package]] +name = "solana-svm-measure" +version = "3.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea1d8035045fe47df97ee2a4695b09236161f82f1b4b6c2a49a5cb6a7c94fed6" + +[[package]] +name = "solana-svm-timings" +version = "3.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9b6407ecacc9b1ca88bdb34f6afb10ab0e4c65f3f1b82bce637c3056deb456d" +dependencies = [ + "eager", + "enum-iterator", + "solana-pubkey 3.0.0", +] + +[[package]] +name = "solana-svm-transaction" +version = "3.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9ca13fa9a99ad8474c3867d56d81effcf5582bb6356ab0a9ed2fc373a3e4af7" +dependencies = [ + "solana-hash 3.1.0", + "solana-message", + "solana-pubkey 3.0.0", + "solana-sdk-ids", + "solana-signature", + "solana-transaction", +] + +[[package]] +name = "solana-svm-type-overrides" +version = "3.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe572aba18afc347a699927720ddc8671da94663a6453e30e872f3ac3788da22" +dependencies = [ + "rand 0.8.5", +] + +[[package]] +name = "solana-system-interface" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e1790547bfc3061f1ee68ea9d8dc6c973c02a163697b24263a8e9f2e6d4afa2" +dependencies = [ + "num-traits", + "serde", + "serde_derive", + "solana-instruction", + "solana-msg", + "solana-program-error", + "solana-pubkey 3.0.0", +] + +[[package]] +name = "solana-system-interface" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14591d6508042ebefb110305d3ba761615927146a26917ade45dc332d8e1ecde" +dependencies = [ + "num-traits", + "serde", + "serde_derive", + "solana-address 2.2.0", + "solana-instruction", + "solana-msg", + "solana-program-error", +] + +[[package]] +name = "solana-sysvar" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6690d3dd88f15c21edff68eb391ef8800df7a1f5cec84ee3e8d1abf05affdf74" +dependencies = [ + "base64 0.22.1", + "bincode", + "bytemuck", + "bytemuck_derive", + "lazy_static", + "serde", + "serde_derive", + "solana-account-info", + "solana-clock", + "solana-define-syscall 4.0.1", + "solana-epoch-rewards", + "solana-epoch-schedule", + "solana-fee-calculator", + "solana-hash 4.2.0", + "solana-instruction", + "solana-last-restart-slot", + "solana-program-entrypoint", + "solana-program-error", + "solana-program-memory", + "solana-pubkey 4.1.0", + "solana-rent", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-slot-hashes", + "solana-slot-history", + "solana-sysvar-id", +] + +[[package]] +name = "solana-sysvar-id" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17358d1e9a13e5b9c2264d301102126cf11a47fd394cdf3dec174fe7bc96e1de" +dependencies = [ + "solana-address 2.2.0", + "solana-sdk-ids", +] + +[[package]] +name = "solana-time-utils" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ced92c60aa76ec4780a9d93f3bd64dfa916e1b998eacc6f1c110f3f444f02c9" + +[[package]] +name = "solana-tls-utils" +version = "3.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3460fa9475f912185e11e89d496ef08aae9db26d0c95a622d71b59e17dd0af8f" +dependencies = [ + "rustls 0.23.36", + "solana-keypair", + "solana-pubkey 3.0.0", + "solana-signer", + "x509-parser", +] + +[[package]] +name = "solana-tpu-client" +version = "3.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b82d41c68b8ff70ef4a952aa40cbe1a4ffe41a4ff7d329f925568f096e6b3f8b" +dependencies = [ + "async-trait", + "bincode", + "futures-util", + "indexmap", + "indicatif", + "log", + "rayon", + "solana-client-traits", + "solana-clock", + "solana-commitment-config", + "solana-connection-cache", + "solana-epoch-schedule", + "solana-measure", + "solana-message", + "solana-net-utils", + "solana-pubkey 3.0.0", + "solana-pubsub-client", + "solana-quic-definitions", + "solana-rpc-client", + "solana-rpc-client-api", + "solana-signature", + "solana-signer", + "solana-transaction", + "solana-transaction-error", + "thiserror 2.0.18", + "tokio", +] + +[[package]] +name = "solana-transaction" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96697cff5075a028265324255efed226099f6d761ca67342b230d09f72cc48d2" +dependencies = [ + "bincode", + "serde", + "serde_derive", + "solana-address 2.2.0", + "solana-hash 4.2.0", + "solana-instruction", + "solana-instruction-error", + "solana-message", + "solana-sanitize", + "solana-sdk-ids", + "solana-short-vec", + "solana-signature", + "solana-signer", + "solana-transaction-error", +] + +[[package]] +name = "solana-transaction-context" +version = "3.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f55a9c2e2af954fae402f08e210c7f01d6a8517ad358f8f0db11ed7de89b02d4" +dependencies = [ + "bincode", + "serde", + "solana-account", + "solana-instruction", + "solana-instructions-sysvar", + "solana-pubkey 3.0.0", + "solana-rent", + "solana-sbpf", + "solana-sdk-ids", +] + +[[package]] +name = "solana-transaction-error" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4222065402340d7e6aec9dc3e54d22992ddcf923d91edcd815443c2bfca3144a" +dependencies = [ + "serde", + "serde_derive", + "solana-instruction-error", + "solana-sanitize", +] + +[[package]] +name = "solana-transaction-metrics-tracker" +version = "3.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de0c780ebbf9ab558a9b9eff409d166c50c81dcbe012b8a488f3f12c042c39c4" +dependencies = [ + "base64 0.22.1", + "bincode", + "log", + "rand 0.8.5", + "solana-packet", + "solana-perf", + "solana-short-vec", + "solana-signature", +] + +[[package]] +name = "solana-transaction-status" +version = "3.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afe59d2c9a9ff1bb05150ebc5b1a945642760977da3715b9e1c403f0a29d3805" +dependencies = [ + "Inflector", + "agave-reserved-account-keys", + "base64 0.22.1", + "bincode", + "borsh", + "bs58", + "log", + "serde", + "serde_json", + "solana-account-decoder", + "solana-address-lookup-table-interface", + "solana-clock", + "solana-hash 3.1.0", + "solana-instruction", + "solana-loader-v2-interface", + "solana-loader-v3-interface", + "solana-message", + "solana-program-option", + "solana-pubkey 3.0.0", + "solana-reward-info", + "solana-sdk-ids", + "solana-signature", + "solana-stake-interface", + "solana-system-interface 2.0.0", + "solana-transaction", + "solana-transaction-error", + "solana-transaction-status-client-types", + "solana-vote-interface", + "spl-associated-token-account-interface", + "spl-memo-interface", + "spl-token-2022-interface", + "spl-token-group-interface", + "spl-token-interface", + "spl-token-metadata-interface", + "thiserror 2.0.18", +] + +[[package]] +name = "solana-transaction-status-client-types" +version = "3.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1341840c0ba1028b918b03c9ba9900019f739ee23946baf76574ec0a5dab8231" +dependencies = [ + "base64 0.22.1", + "bincode", + "bs58", + "serde", + "serde_json", + "solana-account-decoder-client-types", + "solana-commitment-config", + "solana-instruction", + "solana-message", + "solana-pubkey 3.0.0", + "solana-reward-info", + "solana-signature", + "solana-transaction", + "solana-transaction-context", + "solana-transaction-error", + "thiserror 2.0.18", +] + +[[package]] +name = "solana-udp-client" +version = "3.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02efe0168dc03038aadcf3915defa3e8440e705898d9c1cdac99cb70ef20c275" +dependencies = [ + "async-trait", + "solana-connection-cache", + "solana-keypair", + "solana-net-utils", + "solana-streamer", + "solana-transaction-error", + "thiserror 2.0.18", + "tokio", +] + +[[package]] +name = "solana-version" +version = "3.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2642d930b9ef476bfb5d64bac62d35b37dfb415cdf7b0a642c3c0ca537f1a7b" +dependencies = [ + "agave-feature-set", + "rand 0.8.5", + "semver", + "serde", + "solana-sanitize", + "solana-serde-varint", +] + +[[package]] +name = "solana-vote-interface" +version = "4.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db6e123e16bfdd7a81d71b4c4699e0b29580b619f4cd2ef5b6aae1eb85e8979f" +dependencies = [ + "bincode", + "cfg_eval", + "num-derive", + "num-traits", + "serde", + "serde_derive", + "serde_with", + "solana-clock", + "solana-hash 3.1.0", + "solana-instruction", + "solana-instruction-error", + "solana-pubkey 3.0.0", + "solana-rent", + "solana-sdk-ids", + "solana-serde-varint", + "solana-serialize-utils", + "solana-short-vec", + "solana-system-interface 2.0.0", +] + +[[package]] +name = "solana-vote-program" +version = "3.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de77cc3a9dc9c1247d779db24a5c3bb5cf533855ccfa0ddb12c0c773c26acf4e" +dependencies = [ + "agave-feature-set", + "bincode", + "log", + "num-derive", + "num-traits", + "serde", + "solana-account", + "solana-bincode", + "solana-clock", + "solana-epoch-schedule", + "solana-hash 3.1.0", + "solana-instruction", + "solana-keypair", + "solana-packet", + "solana-program-runtime", + "solana-pubkey 3.0.0", + "solana-rent", + "solana-sdk-ids", + "solana-signer", + "solana-slot-hashes", + "solana-transaction", + "solana-transaction-context", + "solana-vote-interface", + "thiserror 2.0.18", +] + +[[package]] +name = "solana-zk-sdk" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9602bcb1f7af15caef92b91132ec2347e1c51a72ecdbefdaefa3eac4b8711475" +dependencies = [ + "aes-gcm-siv", + "base64 0.22.1", + "bincode", + "bytemuck", + "bytemuck_derive", + "curve25519-dalek", + "getrandom 0.2.17", + "itertools 0.12.1", + "js-sys", + "merlin", + "num-derive", + "num-traits", + "rand 0.8.5", + "serde", + "serde_derive", + "serde_json", + "sha3", + "solana-derivation-path", + "solana-instruction", + "solana-pubkey 3.0.0", + "solana-sdk-ids", + "solana-seed-derivable", + "solana-seed-phrase", + "solana-signature", + "solana-signer", + "subtle", + "thiserror 2.0.18", + "wasm-bindgen", + "zeroize", +] + +[[package]] +name = "spinning_top" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d96d2d1d716fb500937168cc09353ffdc7a012be8475ac7308e1bdf0e3923300" +dependencies = [ + "lock_api", +] + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "spl-associated-token-account" +version = "8.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0242277e290c023de8826f504abcf9206b3cd4e18d9ace4ec59a698b2828e88b" +dependencies = [ + "borsh", + "num-derive", + "num-traits", + "solana-account-info", + "solana-cpi", + "solana-instruction", + "solana-msg", + "solana-program-entrypoint", + "solana-program-error", + "solana-pubkey 3.0.0", + "solana-rent", + "solana-sdk-ids", + "solana-system-interface 2.0.0", + "solana-sysvar", + "spl-associated-token-account-interface", + "spl-token-2022-interface", + "spl-token-interface", + "thiserror 2.0.18", +] + +[[package]] +name = "spl-associated-token-account-interface" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6433917b60441d68d99a17e121d9db0ea15a9a69c0e5afa34649cf5ba12612f" +dependencies = [ + "borsh", + "solana-instruction", + "solana-pubkey 3.0.0", +] + +[[package]] +name = "spl-discriminator" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d48cc11459e265d5b501534144266620289720b4c44522a47bc6b63cd295d2f3" +dependencies = [ + "bytemuck", + "solana-program-error", + "solana-sha256-hasher", + "spl-discriminator-derive", +] + +[[package]] +name = "spl-discriminator-derive" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9e8418ea6269dcfb01c712f0444d2c75542c04448b480e87de59d2865edc750" +dependencies = [ + "quote", + "spl-discriminator-syn", + "syn 2.0.115", +] + +[[package]] +name = "spl-discriminator-syn" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d1dbc82ab91422345b6df40a79e2b78c7bce1ebb366da323572dd60b7076b67" +dependencies = [ + "proc-macro2", + "quote", + "sha2", + "syn 2.0.115", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-elgamal-registry" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bd22edf24c47c4610b160f49c12fe33b19aec2a0968e3c9cd412fa2a94ae2bb" +dependencies = [ + "bytemuck", + "solana-account-info", + "solana-cpi", + "solana-instruction", + "solana-msg", + "solana-program-entrypoint", + "solana-program-error", + "solana-pubkey 3.0.0", + "solana-rent", + "solana-sdk-ids", + "solana-security-txt", + "solana-system-interface 2.0.0", + "solana-sysvar", + "solana-zk-sdk", + "spl-elgamal-registry-interface", + "spl-pod", + "spl-token-confidential-transfer-proof-extraction", +] + +[[package]] +name = "spl-elgamal-registry-interface" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "065f54100d118d24036283e03120b2f60cb5b7d597d3db649e13690e22d41398" +dependencies = [ + "bytemuck", + "solana-instruction", + "solana-program-error", + "solana-pubkey 3.0.0", + "solana-sdk-ids", + "solana-zk-sdk", + "spl-token-confidential-transfer-proof-extraction", +] + +[[package]] +name = "spl-generic-token" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233df81b75ab99b42f002b5cdd6e65a7505ffa930624f7096a7580a56765e9cf" +dependencies = [ + "bytemuck", + "solana-pubkey 3.0.0", +] + +[[package]] +name = "spl-memo-interface" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d4e2aedd58f858337fa609af5ad7100d4a243fdaf6a40d6eb4c28c5f19505d3" +dependencies = [ + "solana-instruction", + "solana-pubkey 3.0.0", +] + +[[package]] +name = "spl-pod" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1233fdecd7461611d69bb87bc2e95af742df47291975d21232a0be8217da9de" +dependencies = [ + "borsh", + "bytemuck", + "bytemuck_derive", + "num-derive", + "num-traits", + "num_enum", + "solana-program-error", + "solana-program-option", + "solana-pubkey 3.0.0", + "solana-zk-sdk", + "thiserror 2.0.18", +] + +[[package]] +name = "spl-program-error" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c4f6cf26cb6768110bf024bc7224326c720d711f7ad25d16f40f6cee40edb2d" +dependencies = [ + "num-derive", + "num-traits", + "num_enum", + "solana-msg", + "solana-program-error", + "spl-program-error-derive", + "thiserror 2.0.18", +] + +[[package]] +name = "spl-program-error-derive" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ec8965aa4dc6c74701cbb48b9cad5af35b9a394514934949edbb357b78f840d" +dependencies = [ + "proc-macro2", + "quote", + "sha2", + "syn 2.0.115", +] + +[[package]] +name = "spl-record" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fda0eb42ca6387770d7f0e764ecd8fa863f4529e9ff35fbf146576b5f4372587" +dependencies = [ + "bytemuck", + "num-derive", + "num-traits", + "solana-account-info", + "solana-instruction", + "solana-msg", + "solana-program-entrypoint", + "solana-program-error", + "solana-program-pack", + "solana-pubkey 3.0.0", + "solana-rent", + "solana-security-txt", + "thiserror 2.0.18", +] + +[[package]] +name = "spl-tlv-account-resolution" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6927f613c9d7ce20835d3cefb602137cab2518e383a047c0eaa58054a60644c8" +dependencies = [ + "bytemuck", + "num-derive", + "num-traits", + "num_enum", + "solana-account-info", + "solana-instruction", + "solana-program-error", + "solana-pubkey 3.0.0", + "spl-discriminator", + "spl-pod", + "spl-program-error", + "spl-type-length-value", + "thiserror 2.0.18", +] + +[[package]] +name = "spl-token" +version = "9.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "878b0183d51fcd8a53e1604f4c13321894cf53227e6773c529b0d03d499a8dfd" +dependencies = [ + "arrayref", + "bytemuck", + "num-derive", + "num-traits", + "num_enum", + "solana-account-info", + "solana-cpi", + "solana-instruction", + "solana-msg", + "solana-program-entrypoint", + "solana-program-error", + "solana-program-memory", + "solana-program-option", + "solana-program-pack", + "solana-pubkey 3.0.0", + "solana-rent", + "solana-sdk-ids", + "solana-sysvar", + "spl-token-interface", + "thiserror 2.0.18", +] + +[[package]] +name = "spl-token-2022" +version = "10.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "552427d9117528d037daa0e70416d51322c8a33241317210f230304d852be61e" +dependencies = [ + "arrayref", + "bytemuck", + "num-derive", + "num-traits", + "num_enum", + "solana-account-info", + "solana-clock", + "solana-cpi", + "solana-instruction", + "solana-msg", + "solana-program-entrypoint", + "solana-program-error", + "solana-program-memory", + "solana-program-option", + "solana-program-pack", + "solana-pubkey 3.0.0", + "solana-rent", + "solana-sdk-ids", + "solana-security-txt", + "solana-system-interface 2.0.0", + "solana-sysvar", + "solana-zk-sdk", + "spl-elgamal-registry-interface", + "spl-memo-interface", + "spl-pod", + "spl-token-2022-interface", + "spl-token-confidential-transfer-ciphertext-arithmetic", + "spl-token-confidential-transfer-proof-extraction", + "spl-token-confidential-transfer-proof-generation", + "spl-token-group-interface", + "spl-token-metadata-interface", + "spl-transfer-hook-interface", + "thiserror 2.0.18", +] + +[[package]] +name = "spl-token-2022-interface" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fcd81188211f4b3c8a5eba7fd534c7142f9dd026123b3472492782cc72f4dc6" +dependencies = [ + "arrayref", + "bytemuck", + "num-derive", + "num-traits", + "num_enum", + "solana-account-info", + "solana-instruction", + "solana-program-error", + "solana-program-option", + "solana-program-pack", + "solana-pubkey 3.0.0", + "solana-sdk-ids", + "solana-zk-sdk", + "spl-pod", + "spl-token-confidential-transfer-proof-extraction", + "spl-token-confidential-transfer-proof-generation", + "spl-token-group-interface", + "spl-token-metadata-interface", + "spl-type-length-value", + "thiserror 2.0.18", +] + +[[package]] +name = "spl-token-client" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5f87005f510593cc674a4f9f257bedbecfbb35f5aae1b66a65ef9b7dbccdeb5" +dependencies = [ + "async-trait", + "bincode", + "bytemuck", + "futures", + "futures-util", + "solana-account", + "solana-cli-output", + "solana-compute-budget-interface", + "solana-hash 3.1.0", + "solana-instruction", + "solana-message", + "solana-packet", + "solana-program-error", + "solana-program-pack", + "solana-pubkey 3.0.0", + "solana-rpc-client", + "solana-rpc-client-api", + "solana-signature", + "solana-signer", + "solana-system-interface 2.0.0", + "solana-transaction", + "spl-associated-token-account-interface", + "spl-elgamal-registry", + "spl-memo-interface", + "spl-record", + "spl-token-2022", + "spl-token-2022-interface", + "spl-token-confidential-transfer-proof-extraction", + "spl-token-confidential-transfer-proof-generation", + "spl-token-group-interface", + "spl-token-interface", + "spl-token-metadata-interface", + "spl-transfer-hook-interface", + "thiserror 2.0.18", + "tokio", +] + +[[package]] +name = "spl-token-confidential-transfer-ciphertext-arithmetic" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afbeb07f737d868f145512a4bcf9f59da275b7a3483df0add3f71eb812b689fb" +dependencies = [ + "base64 0.22.1", + "bytemuck", + "solana-curve25519", + "solana-zk-sdk", +] + +[[package]] +name = "spl-token-confidential-transfer-proof-extraction" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879a9ebad0d77383d3ea71e7de50503554961ff0f4ef6cbca39ad126e6f6da3a" +dependencies = [ + "bytemuck", + "solana-account-info", + "solana-curve25519", + "solana-instruction", + "solana-instructions-sysvar", + "solana-msg", + "solana-program-error", + "solana-pubkey 3.0.0", + "solana-sdk-ids", + "solana-zk-sdk", + "spl-pod", + "thiserror 2.0.18", +] + +[[package]] +name = "spl-token-confidential-transfer-proof-generation" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0cd59fce3dc00f563c6fa364d67c3f200d278eae681f4dc250240afcfe044b1" +dependencies = [ + "curve25519-dalek", + "solana-zk-sdk", + "thiserror 2.0.18", +] + +[[package]] +name = "spl-token-group-interface" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "452d0f758af20caaa10d9a6f7608232e000d4c74462f248540b3d2ddfa419776" +dependencies = [ + "bytemuck", + "num-derive", + "num-traits", + "num_enum", + "solana-instruction", + "solana-program-error", + "solana-pubkey 3.0.0", + "spl-discriminator", + "spl-pod", + "thiserror 2.0.18", +] + +[[package]] +name = "spl-token-interface" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c564ac05a7c8d8b12e988a37d82695b5ba4db376d07ea98bc4882c81f96c7f3" +dependencies = [ + "arrayref", + "bytemuck", + "num-derive", + "num-traits", + "num_enum", + "solana-instruction", + "solana-program-error", + "solana-program-option", + "solana-program-pack", + "solana-pubkey 3.0.0", + "solana-sdk-ids", + "thiserror 2.0.18", +] + +[[package]] +name = "spl-token-metadata-interface" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c467c7c3bd056f8fe60119e7ec34ddd6f23052c2fa8f1f51999098063b72676" +dependencies = [ + "borsh", + "num-derive", + "num-traits", + "solana-borsh", + "solana-instruction", + "solana-program-error", + "solana-pubkey 3.0.0", + "spl-discriminator", + "spl-pod", + "spl-type-length-value", + "thiserror 2.0.18", +] + +[[package]] +name = "spl-transfer-hook-interface" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34b46b8f39bc64a9ab177a0ea8e9a58826db76f8d9d154a2400ee60baef7b1e" +dependencies = [ + "arrayref", + "bytemuck", + "num-derive", + "num-traits", + "solana-account-info", + "solana-cpi", + "solana-instruction", + "solana-msg", + "solana-program-error", + "solana-pubkey 3.0.0", + "solana-sdk-ids", + "solana-system-interface 2.0.0", + "spl-discriminator", + "spl-pod", + "spl-program-error", + "spl-tlv-account-resolution", + "spl-type-length-value", + "thiserror 2.0.18", +] + +[[package]] +name = "spl-type-length-value" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca20a1a19f4507a98ca4b28ff5ed54cac9b9d34ed27863e2bde50a3238f9a6ac" +dependencies = [ + "bytemuck", + "num-derive", + "num-traits", + "num_enum", + "solana-account-info", + "solana-msg", + "solana-program-error", + "spl-discriminator", + "spl-pod", + "thiserror 2.0.18", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.115" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e614ed320ac28113fa64972c4262d5dbc89deacdfd00c34a3e4cea073243c12" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", + "unicode-xid", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation 0.9.4", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "take_mut" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" + +[[package]] +name = "takecell" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20f34339676cdcab560c9a82300c4c2581f68b9369aedf0fae86f2ff9565ff3e" + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "teloxide" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c63345cf32a8850ebddcdd769dc2d5193d5e231262d5dada264b79da01a664da" +dependencies = [ + "aquamarine", + "bytes", + "derive_more", + "dptree", + "futures", + "log", + "mime", + "pin-project", + "serde", + "serde_json", + "serde_with_macros 1.5.2", + "teloxide-core", + "teloxide-macros", + "thiserror 1.0.69", + "tokio", + "tokio-stream", + "tokio-util", + "url", +] + +[[package]] +name = "teloxide-core" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "303db260110c238e3af77bb9dff18bf7a5b5196f783059b0852aab75f91d5a16" +dependencies = [ + "bitflags 1.3.2", + "bytes", + "chrono", + "derive_more", + "either", + "futures", + "log", + "mime", + "never", + "once_cell", + "pin-project", + "rc-box", + "reqwest 0.11.27", + "serde", + "serde_json", + "serde_with_macros 1.5.2", + "take_mut", + "takecell", + "thiserror 1.0.69", + "tokio", + "tokio-util", + "url", + "uuid", +] + +[[package]] +name = "teloxide-macros" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f1d653b093dba5e44cada57a516f572167df37b8a619443e59c8c517bb6d804" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "tempfile" +version = "3.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0136791f7c95b1f6dd99f9cc786b91bb81c3800b639b3478e561ddb7be95e5f1" +dependencies = [ + "fastrand", + "getrandom 0.4.1", + "once_cell", + "rustix", + "windows-sys 0.61.2", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width 0.1.14", +] + +[[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 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]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "threadpool" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" +dependencies = [ + "num_cpus", +] + +[[package]] +name = "time" +version = "0.3.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde_core", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" + +[[package]] +name = "time-macros" +version = "0.2.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tiny-bip39" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a30fd743a02bf35236f6faf99adb03089bb77e91c998dac2c2ad76bb424f668c" +dependencies = [ + "once_cell", + "pbkdf2 0.12.2", + "rand 0.8.5", + "rustc-hash 1.1.0", + "sha2", + "thiserror 1.0.69", + "unicode-normalization", + "wasm-bindgen", + "zeroize", +] + +[[package]] +name = "tinystr" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" +dependencies = [ + "displaydoc", + "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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" +dependencies = [ + "bytes", + "libc", + "mio", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2 0.6.2", + "tokio-macros", + "windows-sys 0.61.2", +] + +[[package]] +name = "tokio-macros" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-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 0.23.36", + "tokio", +] + +[[package]] +name = "tokio-stream" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c83b561d025642014097b66e6c1bb422783339e0909e4429cde4749d1990bc38" +dependencies = [ + "futures-util", + "log", + "tokio", + "tungstenite 0.21.0", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25a406cddcc431a75d3d9afc6a7c0f7428d4891dd973e4d54c56b46127bf857" +dependencies = [ + "futures-util", + "log", + "rustls 0.23.36", + "rustls-pki-types", + "tokio", + "tokio-rustls 0.26.4", + "tungstenite 0.28.0", + "webpki-roots 0.26.11", +] + +[[package]] +name = "tokio-util" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "futures-util", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime 0.6.11", + "toml_edit 0.22.27", +] + +[[package]] +name = "toml_datetime" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_datetime" +version = "0.7.5+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.22.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime 0.6.11", + "toml_write", + "winnow", +] + +[[package]] +name = "toml_edit" +version = "0.23.10+spec-1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269" +dependencies = [ + "indexmap", + "toml_datetime 0.7.5+spec-1.1.0", + "toml_parser", + "winnow", +] + +[[package]] +name = "toml_parser" +version = "1.0.8+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0742ff5ff03ea7e67c8ae6c93cac239e0d9784833362da3f9a9c1da8dfefcbdc" +dependencies = [ + "winnow", +] + +[[package]] +name = "toml_write" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" + +[[package]] +name = "tower" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper 1.0.2", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-http" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" +dependencies = [ + "async-compression", + "bitflags 2.11.0", + "bytes", + "futures-core", + "futures-util", + "http 1.4.0", + "http-body 1.0.1", + "http-body-util", + "iri-string", + "pin-project-lite", + "tokio", + "tokio-util", + "tower", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "log", + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", +] + +[[package]] +name = "trait-variant" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70977707304198400eb4835a78f6a9f928bf41bba420deb8fdb175cd965d77a7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "tungstenite" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ef1a641ea34f399a848dea702823bbecfb4c486f911735368f1f137cb8257e1" +dependencies = [ + "byteorder", + "bytes", + "data-encoding", + "http 1.4.0", + "httparse", + "log", + "rand 0.8.5", + "sha1", + "thiserror 1.0.69", + "url", + "utf-8", +] + +[[package]] +name = "tungstenite" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8628dcc84e5a09eb3d8423d6cb682965dea9133204e8fb3efee74c2a0c259442" +dependencies = [ + "bytes", + "data-encoding", + "http 1.4.0", + "httparse", + "log", + "rand 0.9.2", + "rustls 0.23.36", + "rustls-pki-types", + "sha1", + "thiserror 2.0.18", + "utf-8", + "webpki-roots 0.26.11", +] + +[[package]] +name = "typenum" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" + +[[package]] +name = "unicase" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" + +[[package]] +name = "unicode-ident" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "537dd038a89878be9b64dd4bd1b260315c1bb94f4d784956b81e27a088d9a09e" + +[[package]] +name = "unicode-normalization" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + +[[package]] +name = "unicode-width" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "unit-prefix" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81e544489bf3d8ef66c953931f56617f423cd4b5494be343d9b9d3dda037b9a3" + +[[package]] +name = "universal-hash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +dependencies = [ + "crypto-common", + "subtle", +] + +[[package]] +name = "unreachable" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" +dependencies = [ + "void", +] + +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "uriparse" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0200d0fc04d809396c2ad43f3c95da3582a2556eba8d453c1087f4120ee352ff" +dependencies = [ + "fnv", + "lazy_static", +] + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", + "serde_derive", +] + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "uuid" +version = "1.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b672338555252d43fd2240c714dc444b8c6fb0a5c5335e65a07bba7742735ddb" +dependencies = [ + "getrandom 0.4.1", + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.2+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70a6e77fd0ae8029c9ea0063f87c46fde723e7d887703d74ad2616d792e51e6f" +dependencies = [ + "cfg-if", + "futures-util", + "js-sys", + "once_cell", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn 2.0.115", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12" +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", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasm-streams" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags 2.11.0", + "hashbrown 0.15.2", + "indexmap", + "semver", +] + +[[package]] +name = "web-sys" +version = "0.3.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "312e32e551d92129218ea9a2452120f4aabc03529ef03e4d0d82fb2780608598" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[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.25.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" + +[[package]] +name = "webpki-roots" +version = "0.26.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" +dependencies = [ + "webpki-roots 1.0.6", +] + +[[package]] +name = "webpki-roots" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "wincode" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "466e67917609b2d40a838a5b972d1a6237c9749600cb8de8f65559b90d48485b" +dependencies = [ + "pastey", + "proc-macro2", + "quote", + "thiserror 2.0.18", + "wincode-derive", +] + +[[package]] +name = "wincode-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26a7a568eda854acc9945ed136a9d50b8c6d31911584624958808ae96eee3912" +dependencies = [ + "darling 0.21.3", + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.5", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_gnullvm" +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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_aarch64_msvc" +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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_gnullvm" +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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_i686_msvc" +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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnu" +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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_gnullvm" +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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + +[[package]] +name = "winnow" +version = "0.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" +dependencies = [ + "memchr", +] + +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + +[[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 0.5.0", + "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 0.5.0", + "indexmap", + "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.11.0", + "indexmap", + "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", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] + +[[package]] +name = "writeable" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "x509-parser" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0ecbeb7b67ce215e40e3cc7f2ff902f94a223acf44995934763467e7b1febc8" +dependencies = [ + "asn1-rs", + "base64 0.13.1", + "data-encoding", + "der-parser", + "lazy_static", + "nom", + "oid-registry", + "rusticata-macros", + "thiserror 1.0.69", + "time", +] + +[[package]] +name = "yoke" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", + "synstructure 0.13.2", +] + +[[package]] +name = "zerocopy" +version = "0.8.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db6d35d663eadb6c932438e763b262fe1a70987f9ae936e60158176d710cae4a" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4122cd3169e94605190e77839c9a40d40ed048d305bfdc146e7df40ab0f3e517" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", + "synstructure 0.13.2", +] + +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "zerotrie" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.115", +] + +[[package]] +name = "zmij" +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 = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml new file mode 100644 index 0000000..bad7d6f --- /dev/null +++ b/fuzz/Cargo.toml @@ -0,0 +1,49 @@ +[package] +name = "sniper-fuzz" +version = "0.0.0" +publish = false +edition = "2024" + +[package.metadata] +cargo-fuzz = true + +[dependencies] +libfuzzer-sys = "0.4" + +[dependencies.sniper] +path = ".." + +[[bin]] +name = "fuzz_log_parser" +path = "fuzz_targets/fuzz_log_parser.rs" +test = false +doc = false +bench = false + +[[bin]] +name = "fuzz_pool_filter" +path = "fuzz_targets/fuzz_pool_filter.rs" +test = false +doc = false +bench = false + +[[bin]] +name = "fuzz_sol_amount" +path = "fuzz_targets/fuzz_sol_amount.rs" +test = false +doc = false +bench = false + +[[bin]] +name = "fuzz_rule_primitives" +path = "fuzz_targets/fuzz_rule_primitives.rs" +test = false +doc = false +bench = false + +[[bin]] +name = "fuzz_fpga_dma_payload" +path = "fuzz_targets/fuzz_fpga_dma_payload.rs" +test = false +doc = false +bench = false diff --git a/fuzz/check_tools.sh b/fuzz/check_tools.sh new file mode 100755 index 0000000..5182dae --- /dev/null +++ b/fuzz/check_tools.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +set -euo pipefail + +if ! cargo fuzz --version >/dev/null 2>&1; then + cat >&2 <<'EOF' +cargo-fuzz is not installed. +Install it once with: + CARGO_NET_OFFLINE=false cargo install cargo-fuzz +EOF + exit 1 +fi + +if ! rustup toolchain list | grep -q '^nightly'; then + cat >&2 <<'EOF' +nightly toolchain is not installed. +Install it once with: + rustup toolchain install nightly +EOF + exit 1 +fi diff --git a/fuzz/fuzz_targets/fuzz_fpga_dma_payload.rs b/fuzz/fuzz_targets/fuzz_fpga_dma_payload.rs new file mode 100644 index 0000000..dc3c0be --- /dev/null +++ b/fuzz/fuzz_targets/fuzz_fpga_dma_payload.rs @@ -0,0 +1,8 @@ +#![no_main] + +use libfuzzer_sys::fuzz_target; +use sniper::adapters::fpga_feed::decode_dma_payload; + +fuzz_target!(|data: &[u8]| { + let _ = decode_dma_payload(data); +}); diff --git a/fuzz/fuzz_targets/fuzz_log_parser.rs b/fuzz/fuzz_targets/fuzz_log_parser.rs new file mode 100644 index 0000000..efe61fe --- /dev/null +++ b/fuzz/fuzz_targets/fuzz_log_parser.rs @@ -0,0 +1,13 @@ +#![no_main] + +use libfuzzer_sys::fuzz_target; +use sniper::slices::sniper::log_parser::{extract_i64_after_prefix, extract_u64_after_prefix}; + +fuzz_target!(|data: &[u8]| { + let text = String::from_utf8_lossy(data); + let logs = text.lines().map(|line| line.to_owned()).collect::>(); + + let _ = extract_u64_after_prefix(&logs, "vault_0_amount:"); + let _ = extract_u64_after_prefix(&logs, "vault_1_amount:"); + let _ = extract_i64_after_prefix(&logs, "open_time: "); +}); diff --git a/fuzz/fuzz_targets/fuzz_pool_filter.rs b/fuzz/fuzz_targets/fuzz_pool_filter.rs new file mode 100644 index 0000000..324d369 --- /dev/null +++ b/fuzz/fuzz_targets/fuzz_pool_filter.rs @@ -0,0 +1,17 @@ +#![no_main] + +use libfuzzer_sys::fuzz_target; +use sniper::slices::sniper::pool_filter::{ + is_cpmm_candidate_logs, is_openbook_candidate_logs, is_pool_creation_candidate_logs, + is_pool_creation_dma_payload, +}; + +fuzz_target!(|data: &[u8]| { + let _ = is_pool_creation_dma_payload(data); + + let text = String::from_utf8_lossy(data); + let logs = text.lines().map(|line| line.to_owned()).collect::>(); + let _ = is_cpmm_candidate_logs(&logs); + let _ = is_openbook_candidate_logs(&logs); + let _ = is_pool_creation_candidate_logs(&logs); +}); diff --git a/fuzz/fuzz_targets/fuzz_rule_primitives.rs b/fuzz/fuzz_targets/fuzz_rule_primitives.rs new file mode 100644 index 0000000..6bce4a1 --- /dev/null +++ b/fuzz/fuzz_targets/fuzz_rule_primitives.rs @@ -0,0 +1,10 @@ +#![no_main] + +use libfuzzer_sys::fuzz_target; +use sniper::domain::value_objects::{RuleAddress, RuleSlippageBps}; + +fuzz_target!(|data: &[u8]| { + let input = String::from_utf8_lossy(data); + let _ = RuleAddress::try_from(input.as_ref()); + let _ = RuleSlippageBps::from_pct_str(input.as_ref()); +}); diff --git a/fuzz/fuzz_targets/fuzz_sol_amount.rs b/fuzz/fuzz_targets/fuzz_sol_amount.rs new file mode 100644 index 0000000..2c66450 --- /dev/null +++ b/fuzz/fuzz_targets/fuzz_sol_amount.rs @@ -0,0 +1,16 @@ +#![no_main] + +use libfuzzer_sys::fuzz_target; +use sniper::domain::value_objects::sol_amount::parse_positive_sol_str_to_lamports; + +fuzz_target!(|data: &[u8]| { + let raw = String::from_utf8_lossy(data); + let parsed = parse_positive_sol_str_to_lamports(raw.as_ref()); + if let Some(lamports) = parsed { + let formatted = lamports.as_sol_string(); + let round_trip = parse_positive_sol_str_to_lamports(&formatted); + if let Some(round_trip) = round_trip { + let _ = round_trip.as_u64().saturating_sub(lamports.as_u64()); + } + } +}); diff --git a/fuzz/run_all.sh b/fuzz/run_all.sh new file mode 100755 index 0000000..e489614 --- /dev/null +++ b/fuzz/run_all.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -euo pipefail + +max_seconds="${1:-30}" +targets=( + "fuzz_log_parser" + "fuzz_pool_filter" + "fuzz_sol_amount" + "fuzz_rule_primitives" + "fuzz_fpga_dma_payload" +) + +for target in "${targets[@]}"; do + echo "Running ${target} for ${max_seconds}s" + cargo +nightly fuzz run "${target}" -- -max_total_time="${max_seconds}" +done diff --git a/mints.txt b/mints.txt deleted file mode 100644 index 4b27628..0000000 --- a/mints.txt +++ /dev/null @@ -1,3 +0,0 @@ -# Token contract addresses (addys/mints|snipe height|jito tip|slippage -> per line) to snipe -# (snipe height, jito tip and slippage can be a number and a float) - diff --git a/scripts/devnet_bootstrap_and_snipe.sh b/scripts/devnet_bootstrap_and_snipe.sh new file mode 100755 index 0000000..1261dfb --- /dev/null +++ b/scripts/devnet_bootstrap_and_snipe.sh @@ -0,0 +1,250 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd -- "${SCRIPT_DIR}/.." && pwd)" +cd "${REPO_ROOT}" + +CONFIG_PATH="${CONFIG_PATH:-sniper.toml}" +DEVNET_RPC_URL="${DEVNET_RPC_URL:-https://api.devnet.solana.com}" +DEVNET_WSS_URL="${DEVNET_WSS_URL:-wss://api.devnet.solana.com}" +KEYPAIR_PATH="${KEYPAIR_PATH:-keypair.devnet.json}" +SMOKE_TIMEOUT_SECS="${SMOKE_TIMEOUT_SECS:-180}" +PRIORITY_FEES="${PRIORITY_FEES:-1000}" +SNIPE_HEIGHT_SOL="${SNIPE_HEIGHT_SOL:-0.01}" +TIP_BUDGET_SOL="${TIP_BUDGET_SOL:-0.001}" +SLIPPAGE_PCT="${SLIPPAGE_PCT:-1}" +DEVNET_TARGET_MINT="${DEVNET_TARGET_MINT:-}" +MANUAL_FUND_WAIT_SECS="${MANUAL_FUND_WAIT_SECS:-900}" + +require_cmd() { + local command_name="$1" + if ! command -v "${command_name}" >/dev/null 2>&1; then + echo "Missing required command: ${command_name}" >&2 + exit 1 + fi +} + +first_mint_from_config() { + local file_path="$1" + if [[ ! -f "${file_path}" ]]; then + return 0 + fi + + awk ' + /^\[\[rules\]\]/ { + if (in_rule && kind == "mint" && address != "") { + print address + exit + } + in_rule=1 + kind="" + address="" + next + } + in_rule && $1 == "kind" { + value=$3 + gsub(/"/, "", value) + kind=tolower(value) + next + } + in_rule && $1 == "address" { + value=$3 + gsub(/"/, "", value) + address=value + next + } + END { + if (in_rule && kind == "mint" && address != "") { + print address + } + } + ' "${file_path}" +} + +ensure_keypair() { + if [[ -f "${KEYPAIR_PATH}" ]]; then + echo "Using existing keypair: ${KEYPAIR_PATH}" + return 0 + fi + + echo "Creating new devnet keypair: ${KEYPAIR_PATH}" + solana-keygen new \ + --no-bip39-passphrase \ + --silent \ + --force \ + --outfile "${KEYPAIR_PATH}" >/dev/null +} + +current_balance_sol() { + local pubkey="$1" + local raw_balance + raw_balance="$(solana balance "${pubkey}" --url "${DEVNET_RPC_URL}" 2>/dev/null || true)" + awk '{print $1}' <<<"${raw_balance}" +} + +fund_with_one_sol() { + local pubkey="$1" + local balance + balance="$(current_balance_sol "${pubkey}")" + echo "Current balance for ${pubkey}: ${balance:-0} SOL" + + if awk "BEGIN { exit !(${balance:-0} >= 1.0) }"; then + echo "Balance already >= 1 SOL, skipping airdrop." + return 0 + fi + + local attempt + for attempt in $(seq 1 5); do + echo "Airdrop attempt ${attempt}/5: requesting 1 SOL on devnet..." + if ! solana airdrop 1 "${pubkey}" --url "${DEVNET_RPC_URL}"; then + echo "Airdrop attempt ${attempt} failed (likely faucet rate limit)." >&2 + fi + + local wait_index + for wait_index in $(seq 1 5); do + balance="$(current_balance_sol "${pubkey}")" + if awk "BEGIN { exit !(${balance:-0} >= 1.0) }"; then + echo "Balance after funding: ${balance} SOL" + return 0 + fi + sleep 2 + done + done + + echo "Automatic airdrop attempts exhausted." + echo "Manual funding required." + echo "1. Open: https://faucet.solana.com" + echo "2. Select network: devnet" + echo "3. Wallet address: ${pubkey}" + echo "4. Request at least 1 SOL" + + local elapsed=0 + while (( elapsed < MANUAL_FUND_WAIT_SECS )); do + balance="$(current_balance_sol "${pubkey}")" + if awk "BEGIN { exit !(${balance:-0} >= 1.0) }"; then + echo "Manual funding detected. Balance: ${balance} SOL" + return 0 + fi + + sleep 5 + elapsed=$((elapsed + 5)) + done + + echo "Wallet balance is still below 1 SOL after manual wait timeout (${MANUAL_FUND_WAIT_SECS}s)." >&2 + echo "Latest balance: ${balance:-0} SOL" >&2 + exit 1 +} + +resolve_target_mint() { + local mint_from_config + mint_from_config="$(first_mint_from_config "${CONFIG_PATH}")" + + if [[ -n "${DEVNET_TARGET_MINT}" ]]; then + echo "${DEVNET_TARGET_MINT}" + return 0 + fi + + if [[ -n "${mint_from_config}" ]]; then + echo "${mint_from_config}" + return 0 + fi + + echo "No mint rule found in ${CONFIG_PATH} and DEVNET_TARGET_MINT was not set." >&2 + echo "Set DEVNET_TARGET_MINT= and rerun." >&2 + exit 1 +} + +prepare_smoke_config() { + local target_mint="$1" + TMP_SMOKE_CONFIG_PATH="$(mktemp /tmp/sniper.devnet.smoke.XXXXXX.toml)" + export TMP_SMOKE_CONFIG_PATH + + cat > "${TMP_SMOKE_CONFIG_PATH}" <&2 + return "${run_status}" + fi + + echo "Sniper run completed successfully." +} + +main() { + require_cmd "cargo" + require_cmd "solana" + require_cmd "solana-keygen" + require_cmd "timeout" + + solana config set --url "${DEVNET_RPC_URL}" >/dev/null + + ensure_keypair + local pubkey + pubkey="$(solana-keygen pubkey "${KEYPAIR_PATH}")" + + fund_with_one_sol "${pubkey}" + local target_mint + target_mint="$(resolve_target_mint)" + echo "Using target mint: ${target_mint}" + + prepare_smoke_config "${target_mint}" + trap cleanup EXIT + + run_smoke_snipe "${pubkey}" +} + +main "$@" diff --git a/sniper.example.toml b/sniper.example.toml new file mode 100644 index 0000000..e84a6e6 --- /dev/null +++ b/sniper.example.toml @@ -0,0 +1,45 @@ +[runtime] +keypair_path = "keypair.json" +rpc_url = "https://api.mainnet-beta.solana.com" +wss_url = "wss://api.mainnet-beta.solana.com" +priority_fees = 1000000 +tx_submission_mode = "jito" +jito_url = "https://amsterdam.mainnet.block-engine.jito.wtf/api/v1/transactions?bundleOnly=true" +kernel_tcp_bypass = true +# supported: "af_xdp", "dpdk", "openonload", "af_xdp_or_dpdk_external" +kernel_tcp_bypass_engine = "af_xdp_or_dpdk_external" +# used when kernel_tcp_bypass_engine is AF_XDP/DPDK external bridge mode +kernel_bypass_socket_path = "/tmp/sniper-kernel-bypass.sock" +fpga_enabled = false +fpga_verbose = false +fpga_vendor = "generic" +replay_benchmark = false +replay_event_count = 50000 +replay_burst_size = 512 + +[telemetry] +enabled = true +sample_capacity = 4096 +slo_ns = 1000000 +report_period_secs = 15 + +[[rules]] +kind = "mint" +address = "So11111111111111111111111111111111111111112" +snipe_height_sol = "0.01" +tip_budget_sol = "0.001" +slippage_pct = "1" + +[[rules]] +kind = "mint" +address = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" +snipe_height_sol = "0.02" +tip_budget_sol = "0.001" +slippage_pct = "1.5" + +[[rules]] +kind = "deployer" +address = "11111111111111111111111111111111" +snipe_height_sol = "0.01" +tip_budget_sol = "0.001" +slippage_pct = "1" diff --git a/sniper.service b/sniper.service deleted file mode 100644 index 1546217..0000000 --- a/sniper.service +++ /dev/null @@ -1,20 +0,0 @@ -[Unit] -Description=Sniper service -After=network.target - -[Service] -User=sniper -Group=sniper -WorkingDirectory=/home/sniper/sniper -Type=simple -ExecStart=/home/sniper/sniper/target/release/sniper -ExecStartPre=/bin/mkdir -p /home/sniper/sniper/log -ExecStartPre=/bin/chown sniper:sniper /home/sniper/sniper/log -EnvironmentFile=/etc/systemd/system/sniper.env -Restart=on-failure -RestartSec=5s -StartLimitIntervalSec=0 -StartLimitBurst=0 - -[Install] -WantedBy=multi-user.target diff --git a/src/adapters/fpga_feed.rs b/src/adapters/fpga_feed.rs new file mode 100644 index 0000000..c488666 --- /dev/null +++ b/src/adapters/fpga_feed.rs @@ -0,0 +1,411 @@ +use std::{collections::VecDeque, sync::Arc, thread}; + +use tokio::sync::mpsc; + +use crate::{ + domain::events::{ + IngressMetadata, IngressSource, RawLogEvent, normalize_hardware_timestamp_ns, + unix_timestamp_now_ns, + }, + ports::fpga_feed::{FpgaFeedError, FpgaFeedPort}, + slices::sniper::pool_filter::is_pool_creation_dma_payload, +}; + +const MOCK_DMA_VENDOR: &str = "mock_dma"; +const MOCK_DMA_FRAME_ENV: &str = "FPGA_DMA_MOCK_FRAME"; + +#[derive(Clone, Debug)] +struct DmaFrame { + hardware_timestamp_ns: u64, + payload: Arc<[u8]>, +} + +impl DmaFrame { + #[inline(always)] + const fn new(hardware_timestamp_ns: u64, payload: Arc<[u8]>) -> Self { + Self { + hardware_timestamp_ns, + payload, + } + } + + #[inline(always)] + const fn hardware_timestamp_ns(&self) -> u64 { + self.hardware_timestamp_ns + } + + #[inline(always)] + fn payload(&self) -> &[u8] { + &self.payload + } +} + +#[derive(Debug)] +struct DmaRing { + queue: VecDeque, +} + +impl DmaRing { + fn with_capacity(slot_count: usize) -> Self { + Self { + queue: VecDeque::with_capacity(slot_count), + } + } + + fn push(&mut self, frame: DmaFrame) { + self.queue.push_back(frame); + } + + fn pop(&mut self) -> Option { + self.queue.pop_front() + } +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct DecodedDmaPayload { + signature: String, + logs: Vec, + has_error: bool, +} + +impl DecodedDmaPayload { + #[inline(always)] + pub fn signature(&self) -> &str { + &self.signature + } + + #[inline(always)] + pub fn logs(&self) -> &[String] { + &self.logs + } + + #[inline(always)] + pub const fn has_error(&self) -> bool { + self.has_error + } +} + +#[derive(Clone, Debug)] +pub struct FpgaFeedAdapter { + vendor: String, + verbose: bool, + mock_dma_payload: Option>, +} + +impl FpgaFeedAdapter { + #[expect( + clippy::missing_const_for_fn, + reason = "runtime constructor takes owned String and is not used in const contexts" + )] + pub fn new(vendor: String, verbose: bool) -> Self { + Self { + vendor, + verbose, + mock_dma_payload: None, + } + } + + fn bootstrap_dma_ring(&self) -> Result { + if !self.vendor.eq_ignore_ascii_case(MOCK_DMA_VENDOR) { + return Err(FpgaFeedError::Unavailable(format!( + "vendor '{}' does not expose FPGA DMA ring integration yet", + self.vendor + ))); + } + + let payload = self.resolve_mock_dma_payload().ok_or_else(|| { + FpgaFeedError::Unavailable(format!( + "mock FPGA DMA ring requires '{}' environment payload", + MOCK_DMA_FRAME_ENV + )) + })?; + + let frame = DmaFrame::new(unix_timestamp_now_ns(), payload); + let mut ring = DmaRing::with_capacity(1_024); + ring.push(frame); + Ok(ring) + } + + fn resolve_mock_dma_payload(&self) -> Option> { + self.mock_dma_payload.as_ref().map(Arc::clone).or_else(|| { + std::env::var(MOCK_DMA_FRAME_ENV) + .ok() + .map(|payload| Arc::<[u8]>::from(payload.into_bytes())) + }) + } + + fn decode_dma_frame(frame: &DmaFrame) -> Result { + decode_dma_payload(frame.payload()) + } + + pub fn with_mock_dma_payload(vendor: String, verbose: bool, payload: &[u8]) -> Self { + Self { + vendor, + verbose, + mock_dma_payload: Some(Arc::<[u8]>::from(payload)), + } + } + + #[cfg(test)] + fn with_inline_dma_payload(vendor: String, verbose: bool, payload: &[u8]) -> Self { + Self::with_mock_dma_payload(vendor, verbose, payload) + } +} + +impl FpgaFeedPort for FpgaFeedAdapter { + fn vendor(&self) -> &str { + &self.vendor + } + + fn verbose(&self) -> bool { + self.verbose + } + + fn describe(&self) -> String { + if self.verbose { + format!( + "FPGA feed enabled (vendor={}, verbose=true, hardware timestamps active, DMA ring path)", + self.vendor + ) + } else { + format!("FPGA feed enabled (vendor={}, verbose=false)", self.vendor) + } + } + + fn spawn_stream( + &self, + sender: mpsc::UnboundedSender, + ) -> Result<(), FpgaFeedError> { + let mut dma_ring = self.bootstrap_dma_ring()?; + let verbose = self.verbose; + + thread::spawn(move || { + while let Some(frame) = dma_ring.pop() { + if verbose { + log::debug!( + "FPGA DMA RX > ts={} ns, bytes={}", + frame.hardware_timestamp_ns(), + frame.payload().len() + ); + } + + if !is_pool_creation_dma_payload(frame.payload()) { + if verbose { + log::debug!("FPGA DMA RX > frame skipped by deterministic prefilter"); + } + continue; + } + + let parsed = match FpgaFeedAdapter::decode_dma_frame(&frame) { + Ok(value) => value, + Err(error) => { + log::warn!("FPGA DMA decode failed: {}", error); + continue; + } + }; + + let received_timestamp_ns = unix_timestamp_now_ns(); + let normalized_timestamp_ns = normalize_hardware_timestamp_ns( + Some(frame.hardware_timestamp_ns()), + received_timestamp_ns, + ); + let event = RawLogEvent { + signature: parsed.signature, + logs: parsed.logs, + has_error: parsed.has_error, + ingress: IngressMetadata { + source: IngressSource::FpgaDma, + hardware_timestamp_ns: Some(frame.hardware_timestamp_ns()), + received_timestamp_ns, + normalized_timestamp_ns, + }, + }; + + if sender.send(event).is_err() { + log::warn!("FPGA event channel closed. Stopping DMA stream."); + return; + } + } + }); + + Ok(()) + } +} + +pub fn decode_dma_payload(payload: &[u8]) -> Result { + let payload = std::str::from_utf8(payload).map_err(|_parse_error| { + FpgaFeedError::InvalidFrame("FPGA DMA payload is not valid UTF-8".to_owned()) + })?; + + let mut signature: Option = None; + let mut logs = Vec::new(); + let mut has_error = false; + + for line in payload.lines() { + if let Some(value) = line.strip_prefix("signature=") { + if value.trim().is_empty() { + return Err(FpgaFeedError::InvalidFrame( + "FPGA DMA frame contains empty signature".to_owned(), + )); + } + + signature = Some(value.trim().to_owned()); + continue; + } + + if let Some(value) = line.strip_prefix("has_error=") { + has_error = parse_bool_flag(value).ok_or_else(|| { + FpgaFeedError::InvalidFrame("FPGA DMA frame has invalid has_error flag".to_owned()) + })?; + continue; + } + + if let Some(value) = line.strip_prefix("log=") { + logs.push(value.to_owned()); + } + } + + let signature = signature.ok_or_else(|| { + FpgaFeedError::InvalidFrame("FPGA DMA frame missing signature field".to_owned()) + })?; + + if logs.is_empty() { + return Err(FpgaFeedError::InvalidFrame( + "FPGA DMA frame does not contain logs".to_owned(), + )); + } + + Ok(DecodedDmaPayload { + signature, + logs, + has_error, + }) +} + +fn parse_bool_flag(value: &str) -> Option { + let trimmed = value.trim(); + + if trimmed == "1" + || trimmed.eq_ignore_ascii_case("true") + || trimmed.eq_ignore_ascii_case("yes") + || trimmed.eq_ignore_ascii_case("on") + { + return Some(true); + } + + if trimmed == "0" + || trimmed.eq_ignore_ascii_case("false") + || trimmed.eq_ignore_ascii_case("no") + || trimmed.eq_ignore_ascii_case("off") + { + return Some(false); + } + + None +} + +#[cfg(test)] +mod tests { + use std::time::Duration; + + use super::*; + use crate::adapters::raydium::{RAYDIUM_STANDARD_AMM_PROGRAM_ID, RAYDIUM_V4_PROGRAM_ID}; + use crate::ports::fpga_feed::FpgaFeedError; + use tokio::sync::mpsc; + + #[test] + fn fpga_description_contains_vendor() { + let adapter = FpgaFeedAdapter::new("exanic".to_owned(), true); + assert!(adapter.describe().contains("exanic")); + assert!(adapter.verbose()); + assert_eq!(adapter.vendor(), "exanic"); + } + + #[test] + fn dma_frame_parser_builds_strategy_event() { + let frame = DmaFrame::new( + 42, + Arc::<[u8]>::from( + b"signature=5M6A9\nhas_error=0\nlog=Program log: initialize2\nlog=Program log: init_pc_amount: 1," + .as_slice(), + ), + ); + + let parsed = FpgaFeedAdapter::decode_dma_frame(&frame); + assert!(parsed.is_ok()); + + if let Ok(event) = parsed { + assert_eq!(event.signature(), "5M6A9"); + assert!(!event.has_error()); + assert_eq!(event.logs().len(), 2); + } + } + + #[test] + fn decode_dma_payload_rejects_invalid_utf8() { + let decoded = decode_dma_payload(&[0x80, 0xFF, 0x00]); + assert!(decoded.is_err()); + } + + #[test] + fn non_mock_vendor_reports_unavailable_dma_ring() { + let adapter = FpgaFeedAdapter::new("exanic".to_owned(), false); + let (sender, _receiver) = mpsc::unbounded_channel(); + + let result = adapter.spawn_stream(sender); + assert!(result.is_err()); + + if let Err(error) = result { + assert!(matches!(error, FpgaFeedError::Unavailable(_))); + } + } + + #[tokio::test] + async fn mock_dma_vendor_streams_events() { + let adapter = FpgaFeedAdapter::with_inline_dma_payload( + MOCK_DMA_VENDOR.to_owned(), + false, + format!( + "signature=abc123\nhas_error=false\nlog=Program {} logs\nlog=Program log: initialize2", + RAYDIUM_V4_PROGRAM_ID + ) + .as_bytes(), + ); + let (sender, mut receiver) = mpsc::unbounded_channel(); + + let spawned = adapter.spawn_stream(sender); + assert!(spawned.is_ok()); + + let received = tokio::time::timeout(Duration::from_secs(1), receiver.recv()).await; + assert!(received.is_ok()); + + if let Ok(event) = received { + assert!(event.is_some()); + + if let Some(event) = event { + assert_eq!(event.signature, "abc123"); + assert_eq!(event.logs.len(), 2); + assert!(!event.has_error); + assert_eq!(event.ingress.source.as_str(), "fpga_dma"); + } + } + } + + #[test] + fn deterministic_prefilter_accepts_pool_creation() { + let payload = format!( + "log=Program {}\nlog=Program log: initialize2", + RAYDIUM_V4_PROGRAM_ID + ); + assert!(is_pool_creation_dma_payload(payload.as_bytes())); + } + + #[test] + fn deterministic_prefilter_rejects_swap_frame() { + let payload = format!( + "log=Program {}\nlog=Program log: SwapBaseIn", + RAYDIUM_STANDARD_AMM_PROGRAM_ID + ); + assert!(!is_pool_creation_dma_payload(payload.as_bytes())); + } +} diff --git a/src/adapters/mod.rs b/src/adapters/mod.rs new file mode 100644 index 0000000..09b2c99 --- /dev/null +++ b/src/adapters/mod.rs @@ -0,0 +1,5 @@ +pub mod fpga_feed; +pub mod network_path; +pub mod raydium; +pub mod solana_logs; +pub mod toml_rules; diff --git a/src/adapters/network_path.rs b/src/adapters/network_path.rs new file mode 100644 index 0000000..efbbe7e --- /dev/null +++ b/src/adapters/network_path.rs @@ -0,0 +1,129 @@ +use crate::{ + domain::{ + settings::{NetworkStackMode, RuntimeSettings}, + value_objects::{KernelBypassEngine, NonEmptyText}, + }, + ports::network_path::NetworkPathPort, +}; + +#[derive(Clone, Debug)] +pub struct NetworkPathProfile { + mode: NetworkStackMode, + kernel_bypass_enabled: bool, + kernel_bypass_engine: KernelBypassEngine, + fpga_vendor: NonEmptyText, +} + +impl NetworkPathProfile { + pub fn from_settings(settings: &RuntimeSettings) -> Self { + Self { + mode: settings.network_stack_mode, + kernel_bypass_enabled: settings.kernel_tcp_bypass_enabled, + kernel_bypass_engine: settings.kernel_tcp_bypass_engine, + fpga_vendor: settings.fpga_vendor.clone(), + } + } +} + +impl NetworkPathPort for NetworkPathProfile { + fn mode(&self) -> NetworkStackMode { + self.mode + } + + fn describe(&self) -> String { + match self.mode { + NetworkStackMode::Fpga => format!( + "fpga path active via {} NIC (hardware timestamp and deterministic queue)", + self.fpga_vendor.as_str() + ), + NetworkStackMode::KernelBypass => format!( + "kernel tcp bypass active via {} (userspace packet path)", + self.kernel_bypass_engine.as_str() + ), + NetworkStackMode::StandardTcp => { + "kernel tcp bypass disabled (standard kernel socket path)".to_owned() + } + } + } + + fn kernel_bypass_enabled(&self) -> bool { + self.kernel_bypass_enabled + } + + fn fpga_enabled(&self) -> bool { + matches!(self.mode, NetworkStackMode::Fpga) + } +} + +#[cfg(test)] +mod tests { + use super::NetworkPathProfile; + use crate::{ + domain::{ + settings::{NetworkStackMode, RuntimeSettings}, + value_objects::{ + KernelBypassEngine, NonEmptyText, PriorityFeesMicrolamports, ReplayBurstSize, + ReplayEventCount, TxSubmissionMode, + }, + }, + ports::network_path::NetworkPathPort, + }; + + fn settings_for(mode: NetworkStackMode) -> Result { + Ok(RuntimeSettings { + config_path: "sniper.toml".to_owned(), + priority_fees: PriorityFeesMicrolamports::new(1), + keypair_path: "keypair.json".to_owned(), + tx_submission_mode: TxSubmissionMode::Jito, + jito_url: "https://jito.example".to_owned(), + rpc_url: "https://rpc.example".to_owned(), + wss_url: NonEmptyText::try_from("wss://wss.example".to_owned())?, + kernel_tcp_bypass_enabled: true, + kernel_tcp_bypass_engine: KernelBypassEngine::AfXdp, + kernel_bypass_socket_path: NonEmptyText::try_from( + "/tmp/sniper-kernel-bypass.sock".to_owned(), + )?, + fpga_enabled: mode == NetworkStackMode::Fpga, + fpga_verbose: false, + fpga_vendor: NonEmptyText::try_from("exanic".to_owned())?, + network_stack_mode: mode, + run_replay_benchmark: false, + replay_event_count: ReplayEventCount::new(50_000)?, + replay_burst_size: ReplayBurstSize::new(512)?, + latency_sample_capacity: 4_096, + latency_slo_ns: 1_000_000, + latency_report_period_secs: 15, + telemetry_enabled: true, + }) + } + + #[test] + fn fpga_mode_describes_vendor() { + let settings = settings_for(NetworkStackMode::Fpga); + assert!(settings.is_ok()); + let settings = if let Ok(settings) = settings { + settings + } else { + return; + }; + let profile = NetworkPathProfile::from_settings(&settings); + + assert!(profile.fpga_enabled()); + assert!(profile.describe().contains("exanic")); + } + + #[test] + fn standard_mode_disables_fpga() { + let settings = settings_for(NetworkStackMode::StandardTcp); + assert!(settings.is_ok()); + let settings = if let Ok(settings) = settings { + settings + } else { + return; + }; + let profile = NetworkPathProfile::from_settings(&settings); + + assert!(!profile.fpga_enabled()); + assert_eq!(profile.mode(), NetworkStackMode::StandardTcp); + } +} diff --git a/src/adapters/raydium/constants.rs b/src/adapters/raydium/constants.rs new file mode 100644 index 0000000..36c5aaf --- /dev/null +++ b/src/adapters/raydium/constants.rs @@ -0,0 +1,14 @@ +use borsh::{BorshDeserialize, BorshSerialize}; + +pub const STANDARD_AMM_SWAP_BASE_INPUT: [u8; 8] = [143, 190, 90, 218, 196, 30, 51, 222]; +pub const RAYDIUM_STANDARD_AMM_PROGRAM_ID: &str = "CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C"; +pub const RAYDIUM_V4_PROGRAM_ID: &str = "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8"; +pub const TOKEN_PROGRAM_ID: &str = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"; +pub const WSOL_ADDRESS: &str = "So11111111111111111111111111111111111111112"; + +#[derive(BorshSerialize, BorshDeserialize)] +pub struct SwapInstructionBaseIn { + pub discriminator: u8, + pub amount_in: u64, + pub minimum_amount_out: u64, +} diff --git a/src/adapters/raydium/market.rs b/src/adapters/raydium/market.rs new file mode 100644 index 0000000..4873d7b --- /dev/null +++ b/src/adapters/raydium/market.rs @@ -0,0 +1,105 @@ +use std::sync::Arc; + +use solana_client::nonblocking::rpc_client::RpcClient; +use solana_commitment_config::CommitmentConfig; +use solana_sdk::{program_error::ProgramError, pubkey::Pubkey}; + +use crate::MAX_RETRIES; + +const MARKET_STATE_LAYOUT_V3_LEN: usize = 388; +const OWN_ADDRESS_START: usize = 13; +const BASE_VAULT_START: usize = 117; +const QUOTE_VAULT_START: usize = 165; +const EVENT_QUEUE_START: usize = 253; +const BIDS_START: usize = 285; +const ASKS_START: usize = 317; + +#[derive(Debug, Clone)] +pub struct Market { + pub program_id: Pubkey, + pub state: MarketStateLayoutV3, +} + +#[derive(Debug, Clone)] +pub struct MarketStateLayoutV3 { + pub own_address: Pubkey, + pub base_vault: Pubkey, + pub quote_vault: Pubkey, + pub event_queue: Pubkey, + pub bids: Pubkey, + pub asks: Pubkey, +} + +impl MarketStateLayoutV3 { + fn read_pubkey(bytes: &[u8], start: usize) -> Option { + let end = start.checked_add(32)?; + let key_bytes: [u8; 32] = bytes.get(start..end)?.try_into().ok()?; + Some(Pubkey::new_from_array(key_bytes)) + } + + pub fn decode(bytes: &[u8]) -> Option { + if bytes.len() != MARKET_STATE_LAYOUT_V3_LEN { + return None; + } + + Some(Self { + own_address: Self::read_pubkey(bytes, OWN_ADDRESS_START)?, + base_vault: Self::read_pubkey(bytes, BASE_VAULT_START)?, + quote_vault: Self::read_pubkey(bytes, QUOTE_VAULT_START)?, + event_queue: Self::read_pubkey(bytes, EVENT_QUEUE_START)?, + bids: Self::read_pubkey(bytes, BIDS_START)?, + asks: Self::read_pubkey(bytes, ASKS_START)?, + }) + } +} + +pub async fn get_market_accounts(rpc: &Arc, market_id: &Pubkey) -> Option { + let mut attempts = 0_usize; + + loop { + let market_account_info = rpc + .get_account_with_commitment(market_id, CommitmentConfig::confirmed()) + .await; + + match market_account_info { + Ok(response) => { + let account = response.value?; + let state = MarketStateLayoutV3::decode(&account.data)?; + return Some(Market { + program_id: account.owner, + state, + }); + } + Err(error) => { + log::debug!("Error getting market accounts: {}", error); + if attempts >= MAX_RETRIES { + return None; + } + } + } + + tokio::time::sleep(tokio::time::Duration::from_millis(1_000)).await; + attempts = attempts.saturating_add(1); + } +} + +pub fn get_associated_authority( + program_id: &Pubkey, + market_id: &Pubkey, +) -> Result<(Pubkey, u64), ProgramError> { + let market_bytes = market_id.to_bytes(); + let mut nonce = 0_u64; + + while nonce < 100_u64 { + let nonce_bytes = nonce.to_le_bytes(); + let seeds_with_nonce: [&[u8]; 3] = [&market_bytes, &nonce_bytes, &[0_u8; 7]]; + + if let Some((pubkey, _)) = Pubkey::try_find_program_address(&seeds_with_nonce, program_id) { + return Ok((pubkey, nonce)); + } + + nonce = nonce.saturating_add(1); + } + + Err(ProgramError::Custom(1)) +} diff --git a/src/adapters/raydium/mod.rs b/src/adapters/raydium/mod.rs new file mode 100644 index 0000000..2b4bf7c --- /dev/null +++ b/src/adapters/raydium/mod.rs @@ -0,0 +1,10 @@ +pub mod constants; +pub mod market; +pub mod pool; + +pub use constants::{ + RAYDIUM_STANDARD_AMM_PROGRAM_ID, RAYDIUM_V4_PROGRAM_ID, STANDARD_AMM_SWAP_BASE_INPUT, + SwapInstructionBaseIn, TOKEN_PROGRAM_ID, WSOL_ADDRESS, +}; +pub use market::{get_associated_authority, get_market_accounts}; +pub use pool::pool_open_time; diff --git a/src/adapters/raydium/pool.rs b/src/adapters/raydium/pool.rs new file mode 100644 index 0000000..9100729 --- /dev/null +++ b/src/adapters/raydium/pool.rs @@ -0,0 +1,4 @@ +pub fn pool_open_time(data: &[u8]) -> Option { + let pool_open_time_bytes: [u8; 8] = data.get(373..381)?.try_into().ok()?; + Some(u64::from_le_bytes(pool_open_time_bytes)) +} diff --git a/src/adapters/solana_logs.rs b/src/adapters/solana_logs.rs new file mode 100644 index 0000000..822ba1b --- /dev/null +++ b/src/adapters/solana_logs.rs @@ -0,0 +1,304 @@ +use std::{ + io::{BufRead, BufReader}, + thread, + time::Duration, +}; + +#[cfg(unix)] +use std::os::unix::net::UnixStream; + +use serde::Deserialize; +use solana_client::{ + pubsub_client::PubsubClient, + rpc_config::{RpcTransactionLogsConfig, RpcTransactionLogsFilter}, +}; +use solana_commitment_config::CommitmentConfig; +use tokio::sync::mpsc; + +use crate::{ + domain::events::{IngressMetadata, IngressSource, RawLogEvent, unix_timestamp_now_ns}, + domain::value_objects::KernelBypassEngine, + ports::log_stream::{LogStreamError, LogStreamPort}, +}; + +#[derive(Clone, Debug)] +pub struct SolanaPubsubLogStream { + pub wss_url: String, + path_name: &'static str, + source: IngressSource, + kernel_bypass_engine: Option, + kernel_bypass_socket_path: Option, +} + +#[derive(Clone, Debug, Deserialize)] +struct ExternalBypassEvent { + signature: String, + logs: Vec, + #[serde(default)] + has_error: bool, + #[serde(default)] + hardware_timestamp_ns: Option, + #[serde(default)] + received_timestamp_ns: Option, +} + +impl SolanaPubsubLogStream { + pub const fn kernel_bypass( + wss_url: String, + kernel_bypass_engine: KernelBypassEngine, + kernel_bypass_socket_path: String, + ) -> Self { + Self { + wss_url, + path_name: "kernel_bypass", + source: IngressSource::KernelBypass, + kernel_bypass_engine: Some(kernel_bypass_engine), + kernel_bypass_socket_path: Some(kernel_bypass_socket_path), + } + } + + pub const fn standard_tcp(wss_url: String) -> Self { + Self { + wss_url, + path_name: "standard_tcp", + source: IngressSource::StandardTcp, + kernel_bypass_engine: None, + kernel_bypass_socket_path: None, + } + } + + fn validate_ready(&self) -> Result<(), LogStreamError> { + if !self.wss_url.starts_with("wss://") && !self.wss_url.starts_with("ws://") { + return Err(LogStreamError::Unavailable(format!( + "invalid websocket url '{}' for {} path", + self.wss_url, self.path_name + ))); + } + + if self.source == IngressSource::KernelBypass && self.kernel_bypass_engine.is_none() { + return Err(LogStreamError::Unavailable( + "kernel bypass path missing engine selection".to_owned(), + )); + } + + Ok(()) + } + + const fn prefers_external_bypass_feed(&self) -> bool { + matches!( + self.kernel_bypass_engine, + Some( + KernelBypassEngine::AfXdp + | KernelBypassEngine::Dpdk + | KernelBypassEngine::AfXdpOrDpdkExternal + ) + ) + } + + fn spawn_websocket_stream(&self, sender: mpsc::UnboundedSender) { + let wss_url = self.wss_url.clone(); + let source = self.source; + let path_name = self.path_name; + + thread::spawn(move || { + loop { + let logs_filter = RpcTransactionLogsFilter::All; + let logs_config = RpcTransactionLogsConfig { + commitment: Some(CommitmentConfig::confirmed()), + }; + + let ws = match PubsubClient::logs_subscribe(&wss_url, logs_filter, logs_config) { + Ok(value) => value, + Err(error) => { + log::error!("Log subscription failed: {}", error); + thread::sleep(Duration::from_secs(5)); + continue; + } + }; + + log::info!("Listening for tokens on {} path...", path_name); + + while let Ok(response) = ws.1.recv_timeout(Duration::from_secs(30)) { + let received_timestamp_ns = unix_timestamp_now_ns(); + let event = RawLogEvent { + signature: response.value.signature, + logs: response.value.logs, + has_error: response.value.err.is_some(), + ingress: IngressMetadata::from_receive_clock(source, received_timestamp_ns), + }; + + if sender.send(event).is_err() { + log::warn!("Event channel closed. Stopping log stream."); + return; + } + } + + if let Err(error) = ws.0.send_unsubscribe() { + log::debug!("Failed to unsubscribe websocket stream: {}", error); + } + log::warn!("Connection lost, attempting to reconnect in 5 seconds..."); + thread::sleep(Duration::from_secs(5)); + } + }); + } + + #[cfg(unix)] + fn spawn_external_bypass_stream( + &self, + sender: mpsc::UnboundedSender, + ) -> Result<(), LogStreamError> { + let socket_path = self.kernel_bypass_socket_path.clone().ok_or_else(|| { + LogStreamError::Unavailable("Missing kernel bypass socket path".to_owned()) + })?; + + if UnixStream::connect(&socket_path).is_err() { + return Err(LogStreamError::Unavailable(format!( + "kernel bypass socket unavailable at '{}' (expected external AF_XDP/DPDK bridge)", + socket_path + ))); + } + + thread::spawn(move || { + loop { + let stream = match UnixStream::connect(&socket_path) { + Ok(value) => value, + Err(error) => { + log::warn!( + "Kernel bypass socket reconnect failed for '{}': {}", + socket_path, + error + ); + thread::sleep(Duration::from_secs(1)); + continue; + } + }; + + log::info!( + "Listening for tokens on kernel_bypass path via external socket {}", + socket_path + ); + + let mut reader = BufReader::new(stream); + + loop { + let mut frame = String::new(); + let read_len = match reader.read_line(&mut frame) { + Ok(value) => value, + Err(error) => { + log::warn!("Kernel bypass socket read failed: {}", error); + break; + } + }; + + if read_len == 0 { + log::warn!("Kernel bypass socket closed by peer. Reconnecting."); + break; + } + + let payload = frame.trim(); + if payload.is_empty() { + continue; + } + + let parsed = match serde_json::from_str::(payload) { + Ok(value) => value, + Err(error) => { + log::debug!("Kernel bypass frame parse failed: {}", error); + continue; + } + }; + + let received_timestamp_ns = parsed + .received_timestamp_ns + .unwrap_or_else(unix_timestamp_now_ns); + let event = RawLogEvent { + signature: parsed.signature, + logs: parsed.logs, + has_error: parsed.has_error, + ingress: IngressMetadata::from_hardware_clock( + IngressSource::KernelBypass, + parsed.hardware_timestamp_ns, + received_timestamp_ns, + ), + }; + + if sender.send(event).is_err() { + log::warn!("Event channel closed. Stopping kernel bypass stream."); + return; + } + } + + thread::sleep(Duration::from_millis(250)); + } + }); + + Ok(()) + } + + #[cfg(not(unix))] + fn spawn_external_bypass_stream( + &self, + _sender: mpsc::UnboundedSender, + ) -> Result<(), LogStreamError> { + Err(LogStreamError::Unavailable( + "kernel bypass external socket mode requires unix target".to_owned(), + )) + } +} + +impl LogStreamPort for SolanaPubsubLogStream { + fn path_name(&self) -> &'static str { + self.path_name + } + + fn spawn_stream( + &self, + sender: mpsc::UnboundedSender, + ) -> Result<(), LogStreamError> { + self.validate_ready()?; + + if self.source == IngressSource::KernelBypass && self.prefers_external_bypass_feed() { + return self.spawn_external_bypass_stream(sender); + } + + self.spawn_websocket_stream(sender); + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::SolanaPubsubLogStream; + use crate::domain::value_objects::KernelBypassEngine; + use crate::ports::log_stream::{LogStreamError, LogStreamPort}; + use tokio::sync::mpsc; + + #[test] + fn kernel_bypass_requires_valid_url() { + let stream = SolanaPubsubLogStream::kernel_bypass( + "invalid_url".to_owned(), + KernelBypassEngine::AfXdp, + "/tmp/sniper-kernel-bypass.sock".to_owned(), + ); + let (sender, _receiver) = mpsc::unbounded_channel(); + + let started = stream.spawn_stream(sender); + assert!(started.is_err()); + if let Err(error) = started { + assert!(matches!(error, LogStreamError::Unavailable(_))); + } + } + + #[test] + fn path_name_matches_mode() { + let kernel_stream = SolanaPubsubLogStream::kernel_bypass( + "wss://example".to_owned(), + KernelBypassEngine::AfXdp, + "/tmp/sniper-kernel-bypass.sock".to_owned(), + ); + let standard_stream = SolanaPubsubLogStream::standard_tcp("wss://example".to_owned()); + + assert_eq!(kernel_stream.path_name(), "kernel_bypass"); + assert_eq!(standard_stream.path_name(), "standard_tcp"); + } +} diff --git a/src/adapters/toml_rules.rs b/src/adapters/toml_rules.rs new file mode 100644 index 0000000..b8c552f --- /dev/null +++ b/src/adapters/toml_rules.rs @@ -0,0 +1,244 @@ +use std::{collections::HashSet, io, str::FromStr}; + +use solana_sdk::pubkey::Pubkey; + +use crate::{ + domain::{ + config::{RuleKind, load_sniper_config_file}, + entities::SnipeRule, + value_objects::sol_amount::parse_positive_sol_str_to_lamports, + value_objects::{RuleAddress, RuleSlippageBps, RuleSolAmount}, + }, + ports::rule_repository::RuleRepository, +}; + +#[derive(Clone, Debug)] +pub struct TomlRuleRepository { + config_path: String, +} + +impl TomlRuleRepository { + pub const fn new(config_path: String) -> Self { + Self { config_path } + } + + fn report_invalid(message: &str, initial: bool) { + log::error!("{}", message); + if initial { + std::process::exit(1); + } + } + + fn parse_rule_entry( + kind: RuleKind, + address: &str, + snipe_height_sol: &str, + tip_budget_sol: &str, + slippage_pct: &str, + initial: bool, + ) -> Option { + let file_type = match kind { + RuleKind::Mint => "MINTS", + RuleKind::Deployer => "DEPLOYERS", + }; + + let address = address.trim().to_owned(); + if address.is_empty() { + Self::report_invalid(&format!("{} > Empty address", file_type), initial); + return None; + } + + let snipe_height = match parse_positive_sol_str_to_lamports(snipe_height_sol) { + Some(value) => RuleSolAmount::new(value), + None => { + Self::report_invalid( + &format!( + "{} > Invalid snipe height '{}' on address {}", + file_type, snipe_height_sol, address + ), + initial, + ); + return None; + } + }; + + let jito_tip = match parse_positive_sol_str_to_lamports(tip_budget_sol) { + Some(value) => RuleSolAmount::new(value), + None => { + Self::report_invalid( + &format!( + "{} > Invalid tip budget '{}' on address {}", + file_type, tip_budget_sol, address + ), + initial, + ); + return None; + } + }; + + let slippage = match RuleSlippageBps::from_pct_str(slippage_pct) { + Ok(value) => value, + Err(error) => { + Self::report_invalid( + &format!( + "{} > Invalid slippage '{}' on address {}: {}", + file_type, slippage_pct, address, error + ), + initial, + ); + return None; + } + }; + + if Pubkey::from_str(&address).is_err() { + Self::report_invalid( + &format!("{} > Invalid address {}", file_type, address), + initial, + ); + return None; + } + + let address = match RuleAddress::try_from(address) { + Ok(value) => value, + Err(error) => { + Self::report_invalid(&format!("{} > {}", file_type, error), initial); + return None; + } + }; + + Some(SnipeRule::new(address, snipe_height, jito_tip, slippage)) + } +} + +impl RuleRepository for TomlRuleRepository { + async fn load_rules( + &self, + file_type: &str, + initial: bool, + ) -> Result, io::Error> { + let config = load_sniper_config_file(&self.config_path).map_err(|message| { + io::Error::new( + io::ErrorKind::InvalidData, + format!("config parse failed: {}", message), + ) + })?; + + let expected_kind = match file_type { + "MINTS" => RuleKind::Mint, + "DEPLOYERS" => RuleKind::Deployer, + _ => { + return Err(io::Error::new( + io::ErrorKind::InvalidInput, + format!("unsupported rule file type '{}'", file_type), + )); + } + }; + + let mut rules = Vec::new(); + let mut seen_addresses = HashSet::new(); + + for entry in config + .rules + .iter() + .filter(|rule| rule.kind == expected_kind) + { + let parsed_rule = Self::parse_rule_entry( + expected_kind, + &entry.address, + &entry.snipe_height_sol, + &entry.tip_budget_sol, + &entry.slippage_pct, + initial, + ); + + if let Some(rule) = parsed_rule { + if !seen_addresses.insert(rule.address().clone()) { + Self::report_invalid( + &format!( + "{} > Same address used multiple times {}", + file_type, + rule.address() + ), + initial, + ); + continue; + } + + rules.push(rule); + } + } + + Ok(rules) + } +} + +#[cfg(test)] +mod tests { + use super::TomlRuleRepository; + use crate::ports::rule_repository::RuleRepository; + use std::path::PathBuf; + use tokio::fs; + + #[tokio::test] + async fn loads_mint_and_deployer_rules_from_toml() { + let config_path = temp_config_path("toml_rules_load"); + let write_result = fs::write( + &config_path, + r#" +[runtime] +keypair_path = "keypair.json" +rpc_url = "https://rpc.example" +wss_url = "wss://wss.example" +priority_fees = 1000 +tx_submission_mode = "direct" +kernel_tcp_bypass = false +kernel_tcp_bypass_engine = "af_xdp" +fpga_enabled = false +fpga_verbose = false +fpga_vendor = "generic" +replay_benchmark = false +replay_event_count = 50000 +replay_burst_size = 512 + +[[rules]] +kind = "mint" +address = "So11111111111111111111111111111111111111112" +snipe_height_sol = "0.01" +tip_budget_sol = "0.001" +slippage_pct = "1" + +[[rules]] +kind = "deployer" +address = "11111111111111111111111111111111" +snipe_height_sol = "0.02" +tip_budget_sol = "0.001" +slippage_pct = "1" +"#, + ) + .await; + assert!(write_result.is_ok()); + + let repository = TomlRuleRepository::new(config_path.to_string_lossy().into_owned()); + let mint_rules = repository.load_rules("MINTS", false).await; + let deployer_rules = repository.load_rules("DEPLOYERS", false).await; + + assert!(mint_rules.is_ok()); + assert!(deployer_rules.is_ok()); + if let (Ok(mint_rules), Ok(deployer_rules)) = (mint_rules, deployer_rules) { + assert_eq!(mint_rules.len(), 1); + assert_eq!(deployer_rules.len(), 1); + } + + let cleanup_result = fs::remove_file(&config_path).await; + assert!(cleanup_result.is_ok()); + } + + fn temp_config_path(prefix: &str) -> PathBuf { + let file_name = format!( + "{}_{}.toml", + prefix, + crate::domain::events::unix_timestamp_now_ns() + ); + std::env::temp_dir().join(file_name) + } +} diff --git a/src/app/bootstrap.rs b/src/app/bootstrap.rs new file mode 100644 index 0000000..3ace6f4 --- /dev/null +++ b/src/app/bootstrap.rs @@ -0,0 +1,266 @@ +use std::sync::Arc; + +use log::LevelFilter; +use solana_client::nonblocking::rpc_client::RpcClient; +use solana_sdk::{signature::Keypair, signer::Signer}; +use tokio::{ + fs::File, + io::AsyncReadExt, + sync::{mpsc, watch}, +}; + +use crate::{ + adapters::{ + fpga_feed::FpgaFeedAdapter, network_path::NetworkPathProfile, + solana_logs::SolanaPubsubLogStream, toml_rules::TomlRuleRepository, + }, + app::{ + context::ExecutionContext, logging::init_logging, systemd::maybe_handle_service_command, + }, + domain::{settings::RuntimeSettings, value_objects::sol_amount::Lamports}, + ports::{fpga_feed::FpgaFeedPort, log_stream::LogStreamPort, network_path::NetworkPathPort}, + slices::{ + config_sync::service::{ConfigSyncService, load_rulebook}, + sniper::{ + engine::SniperEngine, + replay::{log_replay_report, run_synthetic_replay}, + telemetry::LatencyTelemetry, + }, + }, +}; + +pub async fn run() { + if let Err(error) = run_inner().await { + eprintln!("{}", error); + std::process::exit(1); + } +} + +async fn run_inner() -> Result<(), String> { + let args = std::env::args().skip(1).collect::>(); + if maybe_handle_service_command(&args)? { + return Ok(()); + } + + init_logging(resolve_level_filter()).await?; + + log::info!("Hyper Sniper"); + + let settings = RuntimeSettings::from_cli_args(&args)?; + + if settings.run_replay_benchmark { + let report = run_synthetic_replay( + settings.replay_event_count.get(), + settings.replay_burst_size.get(), + ); + log_replay_report(&report); + return Ok(()); + } + + let keypair = Arc::new(load_keypair(&settings.keypair_path).await?); + let rpc = Arc::new(RpcClient::new(settings.rpc_url.clone())); + + let network_path = NetworkPathProfile::from_settings(&settings); + let fpga_feed = FpgaFeedAdapter::new( + settings.fpga_vendor.as_str().to_owned(), + settings.fpga_verbose, + ); + + let repository = Arc::new(TomlRuleRepository::new(settings.config_path.clone())); + let initial_rulebook = load_rulebook(repository.as_ref(), true) + .await + .map_err(|error| format!("Failed to read rules: {}", error))?; + + let (rulebook_tx, rulebook_rx) = watch::channel(Arc::clone(&initial_rulebook)); + + let config_sync_service = ConfigSyncService::new( + Arc::clone(&repository), + rulebook_tx, + Arc::clone(&initial_rulebook), + ); + config_sync_service.spawn(); + + let balance = rpc + .get_balance(&keypair.pubkey()) + .await + .map(|lamports| Lamports::new(lamports).as_sol_string()) + .map_err(|error| format!("Failed to read wallet balance: {}", error))?; + + let mint_rules = initial_rulebook.mint_log_lines(); + let deployer_rules = initial_rulebook.deployer_log_lines(); + let mints_string = format_rules(&mint_rules); + let deployers_string = format_rules(&deployer_rules); + + log::info!( + "Settings: \ +\n\tWallet: {}\ +\n\tWallet Balance: {} SOL\ +\n\tPRIORITY_FEES: {} µLamports\ +\n\tMINTS:\ +\t\t{}\ +\n\tDEPLOYERS:\ +\t\t{}\ +\n\tTX_SUBMISSION_MODE: {}\ +\n\tJITO_URL: {}\ +\n\tRPC_URL: {}\ +\n\tWSS_URL: {}\ +\n\tNETWORK_STACK_MODE: {}\ +\n\tNETWORK_PATH: {}\ +\n\tKERNEL_TCP_BYPASS: {}\ +\n\tFPGA_ENABLED: {}\ +\n\tTELEMETRY_ENABLED: {}", + keypair.pubkey(), + balance, + settings.priority_fees.as_u64(), + mints_string, + deployers_string, + settings.tx_submission_mode.as_str(), + settings.jito_url, + settings.rpc_url, + settings.wss_url.as_str(), + network_path.mode().as_str(), + network_path.describe(), + network_path.kernel_bypass_enabled(), + network_path.fpga_enabled(), + settings.telemetry_enabled, + ); + + if settings.fpga_enabled { + log::info!( + "FPGA_FEED: {} (vendor={}, verbose={})", + fpga_feed.describe(), + fpga_feed.vendor(), + fpga_feed.verbose(), + ); + } + + let context = Arc::new(ExecutionContext { + priority_fees: settings.priority_fees.as_u64(), + rpc, + keypair, + tx_submission_mode: settings.tx_submission_mode, + jito_url: Arc::new(settings.jito_url.clone()), + }); + + let telemetry = Arc::new(if settings.telemetry_enabled { + LatencyTelemetry::new(settings.latency_sample_capacity, settings.latency_slo_ns) + } else { + LatencyTelemetry::disabled() + }); + Arc::clone(&telemetry).spawn_reporter(std::time::Duration::from_secs( + settings.latency_report_period_secs, + )); + + let (events_tx, events_rx) = mpsc::unbounded_channel(); + let kernel_bypass_stream = SolanaPubsubLogStream::kernel_bypass( + settings.wss_url.as_str().to_owned(), + settings.kernel_tcp_bypass_engine, + settings.kernel_bypass_socket_path.as_str().to_owned(), + ); + let standard_tcp_stream = + SolanaPubsubLogStream::standard_tcp(settings.wss_url.as_str().to_owned()); + + let mut stream_started = false; + + if settings.fpga_enabled { + match fpga_feed.spawn_stream(events_tx.clone()) { + Ok(()) => { + log::info!( + "Ingress path selected: FPGA DMA ring -> strategy events (zero-copy frame parse)" + ); + stream_started = true; + } + Err(error) => { + log::warn!( + "FPGA ingress unavailable: {}. Continuing failover chain.", + error + ); + } + } + } + + if !stream_started && network_path.kernel_bypass_enabled() { + match kernel_bypass_stream.spawn_stream(events_tx.clone()) { + Ok(()) => { + log::info!( + "Ingress path selected: {} -> strategy events", + kernel_bypass_stream.path_name() + ); + stream_started = true; + } + Err(error) => { + log::warn!( + "Kernel bypass ingress unavailable: {}. Falling back to standard tcp path.", + error + ); + } + } + } + + if !stream_started { + standard_tcp_stream + .spawn_stream(events_tx) + .map_err(|error| { + format!( + "Failed to start {} ingress: {}", + standard_tcp_stream.path_name(), + error + ) + })?; + log::info!( + "Ingress path selected: {} -> strategy events", + standard_tcp_stream.path_name() + ); + stream_started = true; + } + + if !stream_started { + return Err("No ingress path could be started".to_owned()); + } + + let engine = SniperEngine::new(context, events_rx, rulebook_rx, telemetry); + engine.run().await; + + Ok(()) +} + +async fn load_keypair(path: &str) -> Result { + let mut keypair_file = File::open(path) + .await + .map_err(|error| format!("Failed to open keypair file: {}", error))?; + + let mut contents = String::new(); + keypair_file + .read_to_string(&mut contents) + .await + .map_err(|error| format!("Failed to read keypair file: {}", error))?; + + let keypair_bytes = serde_json::from_str::>(&contents) + .map_err(|error| format!("Failed to parse keypair json: {}", error))?; + + Keypair::try_from(keypair_bytes.as_slice()) + .map_err(|error| format!("Invalid keypair bytes: {}", error)) +} + +fn resolve_level_filter() -> LevelFilter { + match std::env::var("RUST_LOG") + .unwrap_or_else(|_| "info".to_owned()) + .to_lowercase() + .as_str() + { + "trace" => LevelFilter::Trace, + "debug" => LevelFilter::Debug, + "info" => LevelFilter::Info, + "warn" => LevelFilter::Warn, + "error" => LevelFilter::Error, + _ => LevelFilter::Info, + } +} + +fn format_rules(rules: &[String]) -> String { + if rules.is_empty() { + "(none)".to_owned() + } else { + rules.join("\n\t\t") + } +} diff --git a/src/app/context.rs b/src/app/context.rs new file mode 100644 index 0000000..76c0a24 --- /dev/null +++ b/src/app/context.rs @@ -0,0 +1,15 @@ +use std::sync::Arc; + +use solana_client::nonblocking::rpc_client::RpcClient; +use solana_sdk::signature::Keypair; + +use crate::domain::value_objects::TxSubmissionMode; + +#[derive(Clone)] +pub struct ExecutionContext { + pub priority_fees: u64, + pub rpc: Arc, + pub keypair: Arc, + pub tx_submission_mode: TxSubmissionMode, + pub jito_url: Arc, +} diff --git a/src/app/logging.rs b/src/app/logging.rs new file mode 100644 index 0000000..56b43ad --- /dev/null +++ b/src/app/logging.rs @@ -0,0 +1,166 @@ +use std::{ + fs::OpenOptions, + io::{BufWriter, Write}, + path::PathBuf, + sync::mpsc, + thread, +}; + +use chrono::Local; +use colored::Colorize; +use log::{Level, LevelFilter, Metadata, Record}; +use tokio::fs; + +#[derive(Debug)] +struct AsyncLogEvent { + timestamp: String, + level: Level, + message: String, +} + +#[derive(Debug)] +struct AsyncLogger { + level_filter: LevelFilter, + sender: mpsc::Sender, +} + +impl AsyncLogger { + const fn new(level_filter: LevelFilter, sender: mpsc::Sender) -> Self { + Self { + level_filter, + sender, + } + } +} + +#[derive(Debug)] +struct LogWriter { + receiver: mpsc::Receiver, + log_path: PathBuf, +} + +impl LogWriter { + const fn new(receiver: mpsc::Receiver, log_path: PathBuf) -> Self { + Self { receiver, log_path } + } + + fn run(self) { + let file = OpenOptions::new() + .create(true) + .append(true) + .open(&self.log_path); + let mut file_writer = match file { + Ok(file) => Some(BufWriter::new(file)), + Err(error) => { + eprintln!( + "Failed to open log file '{}': {}", + self.log_path.display(), + error + ); + None + } + }; + + let stdout = std::io::stdout(); + let mut stdout_lock = stdout.lock(); + + while let Ok(event) = self.receiver.recv() { + let console_level = colored_level(event.level); + let file_level = plain_level(event.level); + + if let Err(error) = writeln!( + stdout_lock, + "{} [ {} ] > {}", + event.timestamp, console_level, event.message + ) { + eprintln!("Failed to write log line to stdout: {}", error); + } + + if let Some(writer) = file_writer.as_mut() { + if let Err(error) = writeln!( + writer, + "{} [ {} ] > {}", + event.timestamp, file_level, event.message + ) { + eprintln!("Failed to write log line to file: {}", error); + file_writer = None; + continue; + } + + if let Err(error) = writer.flush() { + eprintln!("Failed to flush log file writer: {}", error); + file_writer = None; + } + } + } + } +} + +impl log::Log for AsyncLogger { + fn enabled(&self, metadata: &Metadata<'_>) -> bool { + metadata.level() <= self.level_filter + } + + fn log(&self, record: &Record<'_>) { + if !self.enabled(record.metadata()) { + return; + } + + let event = AsyncLogEvent { + timestamp: Local::now().format("%Y-%m-%d %H:%M:%S.%3f").to_string(), + level: record.level(), + message: format!("{}", record.args()), + }; + + if let Err(_error) = self.sender.send(event) { + // Logger channel is down; avoid recursive logging. + } + } + + fn flush(&self) {} +} + +pub async fn init_logging(level_filter: LevelFilter) -> Result<(), String> { + let log_dir = PathBuf::from("log"); + fs::create_dir_all(&log_dir) + .await + .map_err(|error| format!("Failed to create log directory: {}", error))?; + + let log_path = log_dir.join("output.ans"); + let (sender, receiver) = mpsc::channel::(); + let writer = LogWriter::new(receiver, log_path); + + thread::spawn(move || { + writer.run(); + }); + + let logger = AsyncLogger::new(level_filter, sender); + if let Err(_error) = log::set_boxed_logger(Box::new(logger)) { + // Logger may already be initialized in process lifecycle. + log::set_max_level(level_filter); + return Ok(()); + } + + log::set_max_level(level_filter); + Ok(()) +} + +fn colored_level(level: Level) -> String { + match level { + Level::Info => "+".green().to_string(), + Level::Error => "-".red().to_string(), + Level::Warn => "!".yellow().to_string(), + Level::Debug => "*".blue().to_string(), + Level::Trace => "~".purple().to_string(), + } +} + +const fn plain_level(level: Level) -> &'static str { + match level { + Level::Info => "+", + Level::Error => "-", + Level::Warn => "!", + Level::Debug => "*", + Level::Trace => "~", + } +} diff --git a/src/app/mod.rs b/src/app/mod.rs new file mode 100644 index 0000000..0cfb66f --- /dev/null +++ b/src/app/mod.rs @@ -0,0 +1,4 @@ +pub mod bootstrap; +pub mod context; +pub mod logging; +pub mod systemd; diff --git a/src/app/systemd.rs b/src/app/systemd.rs new file mode 100644 index 0000000..4bf858c --- /dev/null +++ b/src/app/systemd.rs @@ -0,0 +1,335 @@ +use std::{ + env, fs, + path::{Path, PathBuf}, + process::Command, +}; + +const DEFAULT_SERVICE_NAME: &str = "sniper"; +const DEFAULT_SYSTEMD_DIR: &str = "/etc/systemd/system"; +const DEFAULT_CONFIG_PATH: &str = "sniper.toml"; + +#[derive(Clone, Debug, Eq, PartialEq)] +struct ServiceOptions { + service_name: String, + service_user: String, + service_group: String, + systemd_dir: PathBuf, + config_path: PathBuf, + working_dir: PathBuf, + bin_path: PathBuf, + enable_now: bool, +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +enum ServiceAction { + Install, + Uninstall, +} + +pub fn maybe_handle_service_command(args: &[String]) -> Result { + let install = arg_flag(args, "--install-service"); + let uninstall = arg_flag(args, "--uninstall-service"); + + if !install && !uninstall { + return Ok(false); + } + + if install && uninstall { + return Err("Use only one of --install-service or --uninstall-service".to_owned()); + } + + let action = if install { + ServiceAction::Install + } else { + ServiceAction::Uninstall + }; + let options = build_options(args)?; + + match action { + ServiceAction::Install => install_service(&options)?, + ServiceAction::Uninstall => uninstall_service(&options)?, + } + + Ok(true) +} + +fn build_options(args: &[String]) -> Result { + let service_name = + arg_value(args, "--service-name").unwrap_or_else(|| DEFAULT_SERVICE_NAME.to_owned()); + validate_name(&service_name, "service name")?; + + let service_user = arg_value(args, "--service-user") + .or_else(|| env::var("SUDO_USER").ok()) + .or_else(|| env::var("USER").ok()) + .unwrap_or_else(|| "root".to_owned()); + validate_name(&service_user, "service user")?; + + let service_group = arg_value(args, "--service-group") + .or_else(|| primary_group_for_user(&service_user)) + .unwrap_or_else(|| service_user.clone()); + validate_name(&service_group, "service group")?; + + let systemd_dir = absolutize( + arg_value(args, "--systemd-dir").unwrap_or_else(|| DEFAULT_SYSTEMD_DIR.to_owned()), + )?; + let config_path = + absolutize(arg_value(args, "--config").unwrap_or_else(|| DEFAULT_CONFIG_PATH.to_owned()))?; + let working_dir = + env::current_dir().map_err(|error| format!("Failed to resolve current dir: {}", error))?; + let bin_path = env::current_exe() + .map_err(|error| format!("Failed to resolve current binary path: {}", error))?; + + ensure_no_spaces(&systemd_dir, "systemd dir")?; + ensure_no_spaces(&config_path, "config path")?; + ensure_no_spaces(&working_dir, "working dir")?; + ensure_no_spaces(&bin_path, "binary path")?; + + Ok(ServiceOptions { + service_name, + service_user, + service_group, + systemd_dir, + config_path, + working_dir, + bin_path, + enable_now: !arg_flag(args, "--no-enable"), + }) +} + +fn install_service(options: &ServiceOptions) -> Result<(), String> { + if !options.bin_path.is_file() { + return Err(format!("Binary not found: {}", options.bin_path.display())); + } + + if !options.config_path.is_file() { + return Err(format!( + "Config not found: {}", + options.config_path.display() + )); + } + + fs::create_dir_all(&options.systemd_dir).map_err(|error| { + format!( + "Failed to create systemd dir '{}': {}", + options.systemd_dir.display(), + error + ) + })?; + + let unit_file_name = format!("{}.service", options.service_name); + let unit_file_path = options.systemd_dir.join(&unit_file_name); + let log_dir = options.working_dir.join("log"); + + let unit_contents = render_unit(options, &log_dir); + fs::write(&unit_file_path, unit_contents).map_err(|error| { + format!( + "Failed to write unit file '{}': {}", + unit_file_path.display(), + error + ) + })?; + + run_systemctl(&["daemon-reload"])?; + + if options.enable_now { + run_systemctl(&["enable", "--now", &unit_file_name])?; + println!( + "Installed and started {} using config {}", + unit_file_name, + options.config_path.display() + ); + } else { + println!( + "Installed {} (not enabled/started) using config {}", + unit_file_name, + options.config_path.display() + ); + } + + Ok(()) +} + +fn uninstall_service(options: &ServiceOptions) -> Result<(), String> { + let unit_file_name = format!("{}.service", options.service_name); + let unit_file_path = options.systemd_dir.join(&unit_file_name); + + let _disable_result = run_systemctl(&["disable", "--now", &unit_file_name]); + + if unit_file_path.exists() { + fs::remove_file(&unit_file_path).map_err(|error| { + format!( + "Failed to remove unit file '{}': {}", + unit_file_path.display(), + error + ) + })?; + } + + run_systemctl(&["daemon-reload"])?; + let _reset_failed = run_systemctl(&["reset-failed", &unit_file_name]); + + println!("Uninstalled {}", unit_file_name); + Ok(()) +} + +fn run_systemctl(args: &[&str]) -> Result<(), String> { + let output = Command::new("systemctl") + .args(args) + .output() + .map_err(|error| format!("Failed to execute systemctl {:?}: {}", args, error))?; + + if output.status.success() { + return Ok(()); + } + + let stderr = String::from_utf8_lossy(&output.stderr); + let stdout = String::from_utf8_lossy(&output.stdout); + Err(format!( + "systemctl {:?} failed (code {:?}). stdout='{}' stderr='{}'", + args, + output.status.code(), + stdout.trim(), + stderr.trim() + )) +} + +fn primary_group_for_user(user: &str) -> Option { + let output = Command::new("id").args(["-gn", user]).output().ok()?; + if !output.status.success() { + return None; + } + + let group = String::from_utf8_lossy(&output.stdout).trim().to_owned(); + if group.is_empty() { None } else { Some(group) } +} + +fn render_unit(options: &ServiceOptions, log_dir: &Path) -> String { + format!( + "[Unit] +Description=Sniper service +After=network.target + +[Service] +User={} +Group={} +WorkingDirectory={} +Type=simple +ExecStart={} --config {} +ExecStartPre=/bin/mkdir -p {} +ExecStartPre=/bin/chown {}:{} {} +Restart=on-failure +RestartSec=5s +StartLimitIntervalSec=0 +StartLimitBurst=0 + +[Install] +WantedBy=multi-user.target +", + options.service_user, + options.service_group, + options.working_dir.display(), + options.bin_path.display(), + options.config_path.display(), + log_dir.display(), + options.service_user, + options.service_group, + log_dir.display(), + ) +} + +fn arg_flag(args: &[String], flag: &str) -> bool { + args.iter().any(|arg| arg == flag) +} + +fn arg_value(args: &[String], flag: &str) -> Option { + args.iter() + .position(|arg| arg == flag) + .and_then(|index| args.get(index.saturating_add(1))) + .cloned() +} + +fn absolutize(value: String) -> Result { + let path = PathBuf::from(value); + if path.is_absolute() { + return Ok(path); + } + + env::current_dir() + .map(|cwd| cwd.join(path)) + .map_err(|error| format!("Failed to resolve absolute path: {}", error)) +} + +fn validate_name(value: &str, field: &str) -> Result<(), String> { + if value.trim().is_empty() { + return Err(format!("{} must not be empty", field)); + } + if value.contains(char::is_whitespace) || value.contains('/') { + return Err(format!( + "{} must not contain whitespace or '/' (got '{}')", + field, value + )); + } + Ok(()) +} + +fn ensure_no_spaces(path: &Path, field: &str) -> Result<(), String> { + if path.to_string_lossy().contains(' ') { + return Err(format!( + "{} must not contain spaces for systemd compatibility: {}", + field, + path.display() + )); + } + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::{DEFAULT_SERVICE_NAME, arg_value, maybe_handle_service_command, render_unit}; + use std::path::PathBuf; + + #[test] + fn arg_value_reads_config_flag() { + let args = vec![ + "--install-service".to_owned(), + "--config".to_owned(), + "/tmp/sniper.toml".to_owned(), + ]; + + assert_eq!( + arg_value(&args, "--config"), + Some("/tmp/sniper.toml".to_owned()) + ); + } + + #[test] + fn service_flags_are_mutually_exclusive() { + let args = vec![ + "--install-service".to_owned(), + "--uninstall-service".to_owned(), + ]; + + let result = maybe_handle_service_command(&args); + assert!(result.is_err()); + } + + #[test] + fn unit_template_contains_config_arg() { + let options = super::ServiceOptions { + service_name: DEFAULT_SERVICE_NAME.to_owned(), + service_user: "sniper".to_owned(), + service_group: "sniper".to_owned(), + systemd_dir: PathBuf::from("/etc/systemd/system"), + config_path: PathBuf::from("/home/sniper/sniper/sniper.toml"), + working_dir: PathBuf::from("/home/sniper/sniper"), + bin_path: PathBuf::from("/home/sniper/sniper/target/release/sniper"), + enable_now: true, + }; + let log_dir = PathBuf::from("/home/sniper/sniper/log"); + + let rendered = render_unit(&options, &log_dir); + assert!(rendered.contains( + "ExecStart=/home/sniper/sniper/target/release/sniper --config /home/sniper/sniper/sniper.toml" + )); + } +} diff --git a/src/domain/aggregates/mod.rs b/src/domain/aggregates/mod.rs new file mode 100644 index 0000000..226cefc --- /dev/null +++ b/src/domain/aggregates/mod.rs @@ -0,0 +1,3 @@ +pub mod rule_book; + +pub use rule_book::RuleBook; diff --git a/src/domain/aggregates/rule_book.rs b/src/domain/aggregates/rule_book.rs new file mode 100644 index 0000000..081b0a7 --- /dev/null +++ b/src/domain/aggregates/rule_book.rs @@ -0,0 +1,122 @@ +use std::collections::HashMap; + +use crate::domain::{entities::SnipeRule, value_objects::RuleAddress}; + +#[derive(Clone, Debug, Default, PartialEq)] +pub struct RuleBook { + mint_rules: HashMap, + deployer_rules: HashMap, +} + +impl RuleBook { + pub fn new(mints: Vec, deployers: Vec) -> Self { + let mint_rules = mints + .into_iter() + .map(|rule| (rule.address().clone(), rule)) + .collect::>(); + + let deployer_rules = deployers + .into_iter() + .map(|rule| (rule.address().clone(), rule)) + .collect::>(); + + Self { + mint_rules, + deployer_rules, + } + } + + #[inline(always)] + pub fn mint_rule(&self, token_address: &str) -> Option<&SnipeRule> { + self.mint_rules.get(token_address) + } + + #[inline(always)] + pub fn deployer_rule(&self, deployer_address: &str) -> Option<&SnipeRule> { + self.deployer_rules.get(deployer_address) + } + + pub const fn mint_rules(&self) -> &HashMap { + &self.mint_rules + } + + pub const fn deployer_rules(&self) -> &HashMap { + &self.deployer_rules + } + + pub fn mint_log_lines(&self) -> Vec { + let mut rules = self.mint_rules.values().collect::>(); + rules.sort_by(|left, right| left.address().as_str().cmp(right.address().as_str())); + rules + .iter() + .map(|rule| rule.as_log_line("Token address")) + .collect::>() + } + + pub fn deployer_log_lines(&self) -> Vec { + let mut rules = self.deployer_rules.values().collect::>(); + rules.sort_by(|left, right| left.address().as_str().cmp(right.address().as_str())); + rules + .iter() + .map(|rule| rule.as_log_line("Deployer address")) + .collect::>() + } +} + +#[cfg(test)] +mod tests { + use super::RuleBook; + use crate::domain::{ + entities::SnipeRule, + value_objects::{RuleAddress, RuleSlippageBps, RuleSolAmount, sol_amount::Lamports}, + }; + + fn build_rule(address: &str) -> Option { + let address = RuleAddress::try_from(address).ok()?; + let slippage = RuleSlippageBps::from_pct_str("1").ok()?; + Some(SnipeRule::new( + address, + RuleSolAmount::new(Lamports::new(1_000_000_000)), + RuleSolAmount::new(Lamports::new(100_000_000)), + slippage, + )) + } + + #[test] + fn indexes_mint_and_deployer_rules() { + let mint_rule = build_rule("So11111111111111111111111111111111111111112"); + let deployer_rule = build_rule("11111111111111111111111111111111"); + assert!(mint_rule.is_some()); + assert!(deployer_rule.is_some()); + + if let (Some(mint_rule), Some(deployer_rule)) = (mint_rule, deployer_rule) { + let book = RuleBook::new(vec![mint_rule], vec![deployer_rule]); + assert!( + book.mint_rule("So11111111111111111111111111111111111111112") + .is_some() + ); + assert!( + book.deployer_rule("11111111111111111111111111111111") + .is_some() + ); + } + } + + #[test] + fn emits_sorted_log_lines() { + let mint_a = build_rule("11111111111111111111111111111111"); + let mint_b = build_rule("So11111111111111111111111111111111111111112"); + assert!(mint_a.is_some()); + assert!(mint_b.is_some()); + + if let (Some(mint_a), Some(mint_b)) = (mint_a, mint_b) { + let book = RuleBook::new(vec![mint_b, mint_a], Vec::new()); + let lines = book.mint_log_lines(); + assert_eq!(lines.len(), 2); + assert!(!lines.is_empty()); + if let Some(first_line) = lines.first() { + assert!(first_line.contains("11111111111111111111111111111111")); + } + } + } +} diff --git a/src/domain/config.rs b/src/domain/config.rs new file mode 100644 index 0000000..b486b86 --- /dev/null +++ b/src/domain/config.rs @@ -0,0 +1,213 @@ +use serde::Deserialize; + +#[derive(Clone, Debug, Deserialize)] +pub struct SniperConfigFile { + pub runtime: RuntimeConfigSection, + #[serde(default)] + pub telemetry: TelemetryConfigSection, + #[serde(default)] + pub rules: Vec, +} + +#[derive(Clone, Debug, Deserialize)] +pub struct RuntimeConfigSection { + pub keypair_path: String, + pub rpc_url: String, + pub wss_url: String, + pub priority_fees: u64, + #[serde(default = "default_tx_submission_mode")] + pub tx_submission_mode: String, + #[serde(default)] + pub jito_url: Option, + #[serde(default = "default_kernel_tcp_bypass")] + pub kernel_tcp_bypass: bool, + #[serde(default = "default_kernel_tcp_bypass_engine")] + pub kernel_tcp_bypass_engine: String, + #[serde(default = "default_kernel_bypass_socket_path")] + pub kernel_bypass_socket_path: String, + #[serde(default)] + pub fpga_enabled: bool, + #[serde(default)] + pub fpga_verbose: bool, + #[serde(default = "default_fpga_vendor")] + pub fpga_vendor: String, + #[serde(default)] + pub replay_benchmark: bool, + #[serde(default = "default_replay_event_count")] + pub replay_event_count: usize, + #[serde(default = "default_replay_burst_size")] + pub replay_burst_size: usize, +} + +#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq)] +#[serde(rename_all = "lowercase")] +pub enum RuleKind { + Mint, + Deployer, +} + +#[derive(Clone, Debug, Deserialize)] +pub struct RuleConfigEntry { + pub kind: RuleKind, + pub address: String, + pub snipe_height_sol: String, + pub tip_budget_sol: String, + pub slippage_pct: String, +} + +#[derive(Clone, Debug, Deserialize)] +pub struct TelemetryConfigSection { + #[serde(default = "default_telemetry_enabled")] + pub enabled: bool, + #[serde(default = "default_telemetry_sample_capacity")] + pub sample_capacity: usize, + #[serde(default = "default_telemetry_slo_ns")] + pub slo_ns: u64, + #[serde(default = "default_telemetry_report_period_secs")] + pub report_period_secs: u64, +} + +impl Default for TelemetryConfigSection { + fn default() -> Self { + Self { + enabled: default_telemetry_enabled(), + sample_capacity: default_telemetry_sample_capacity(), + slo_ns: default_telemetry_slo_ns(), + report_period_secs: default_telemetry_report_period_secs(), + } + } +} + +pub fn load_sniper_config_file(path: &str) -> Result { + let config_text = std::fs::read_to_string(path) + .map_err(|error| format!("Failed to read config file '{}': {}", path, error))?; + parse_sniper_config_toml(&config_text) +} + +pub fn parse_sniper_config_toml(config_text: &str) -> Result { + toml::from_str::(config_text) + .map_err(|error| format!("Invalid sniper.toml format: {}", error)) +} + +fn default_tx_submission_mode() -> String { + "jito".to_owned() +} + +const fn default_kernel_tcp_bypass() -> bool { + true +} + +fn default_kernel_tcp_bypass_engine() -> String { + "af_xdp_or_dpdk_external".to_owned() +} + +fn default_kernel_bypass_socket_path() -> String { + "/tmp/sniper-kernel-bypass.sock".to_owned() +} + +fn default_fpga_vendor() -> String { + "generic".to_owned() +} + +const fn default_replay_event_count() -> usize { + 50_000 +} + +const fn default_replay_burst_size() -> usize { + 512 +} + +const fn default_telemetry_sample_capacity() -> usize { + 4_096 +} + +const fn default_telemetry_enabled() -> bool { + true +} + +const fn default_telemetry_slo_ns() -> u64 { + 1_000_000 +} + +const fn default_telemetry_report_period_secs() -> u64 { + 15 +} + +#[cfg(test)] +mod tests { + use super::{RuleKind, parse_sniper_config_toml}; + + #[test] + fn parses_runtime_and_rules_from_toml() { + let config = parse_sniper_config_toml( + r#" +[runtime] +keypair_path = "keypair.json" +rpc_url = "https://rpc.example" +wss_url = "wss://wss.example" +priority_fees = 1000 +tx_submission_mode = "direct" +jito_url = "https://jito.example" +kernel_tcp_bypass = false +kernel_tcp_bypass_engine = "af_xdp" +fpga_enabled = false +fpga_verbose = false +fpga_vendor = "generic" +replay_benchmark = false +replay_event_count = 50000 +replay_burst_size = 512 + +[telemetry] +enabled = true +sample_capacity = 1024 +slo_ns = 500000 +report_period_secs = 5 + +[[rules]] +kind = "mint" +address = "So11111111111111111111111111111111111111112" +snipe_height_sol = "0.01" +tip_budget_sol = "0.001" +slippage_pct = "1" +"#, + ); + + assert!(config.is_ok()); + if let Ok(config) = config { + assert_eq!(config.runtime.priority_fees, 1_000); + assert!(config.telemetry.enabled); + assert_eq!(config.telemetry.sample_capacity, 1_024); + assert_eq!(config.rules.len(), 1); + if let Some(rule) = config.rules.first() { + assert_eq!(rule.kind, RuleKind::Mint); + } + } + } + + #[test] + fn telemetry_enabled_defaults_to_true() { + let config = parse_sniper_config_toml( + r#" +[runtime] +keypair_path = "keypair.json" +rpc_url = "https://rpc.example" +wss_url = "wss://wss.example" +priority_fees = 1000 +tx_submission_mode = "direct" +kernel_tcp_bypass = false +kernel_tcp_bypass_engine = "af_xdp" +fpga_enabled = false +fpga_verbose = false +fpga_vendor = "generic" +replay_benchmark = false +replay_event_count = 50000 +replay_burst_size = 512 +"#, + ); + + assert!(config.is_ok()); + if let Ok(config) = config { + assert!(config.telemetry.enabled); + } + } +} diff --git a/src/domain/entities/mod.rs b/src/domain/entities/mod.rs new file mode 100644 index 0000000..4c790b1 --- /dev/null +++ b/src/domain/entities/mod.rs @@ -0,0 +1,3 @@ +pub mod snipe_rule; + +pub use snipe_rule::{SnipeRule, SnipeRuleCold, SnipeRuleHot}; diff --git a/src/domain/entities/snipe_rule.rs b/src/domain/entities/snipe_rule.rs new file mode 100644 index 0000000..bd5b1a3 --- /dev/null +++ b/src/domain/entities/snipe_rule.rs @@ -0,0 +1,156 @@ +use std::sync::Arc; + +use crate::domain::value_objects::{RuleAddress, RuleSlippageBps, RuleSolAmount}; + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct SnipeRuleHot { + snipe_height: RuleSolAmount, + jito_tip: RuleSolAmount, + slippage: RuleSlippageBps, +} + +impl SnipeRuleHot { + #[inline(always)] + pub const fn new( + snipe_height: RuleSolAmount, + jito_tip: RuleSolAmount, + slippage: RuleSlippageBps, + ) -> Self { + Self { + snipe_height, + jito_tip, + slippage, + } + } + + #[inline(always)] + pub const fn snipe_height(self) -> RuleSolAmount { + self.snipe_height + } + + #[inline(always)] + pub const fn jito_tip(self) -> RuleSolAmount { + self.jito_tip + } + + #[inline(always)] + pub const fn slippage(self) -> RuleSlippageBps { + self.slippage + } +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct SnipeRuleCold { + pub address: RuleAddress, +} + +#[derive(Clone, Debug, PartialEq)] +pub struct SnipeRule { + hot: SnipeRuleHot, + cold: Arc, +} + +impl SnipeRule { + #[inline(always)] + pub fn new( + address: RuleAddress, + snipe_height: RuleSolAmount, + jito_tip: RuleSolAmount, + slippage: RuleSlippageBps, + ) -> Self { + Self { + hot: SnipeRuleHot::new(snipe_height, jito_tip, slippage), + cold: Arc::new(SnipeRuleCold { address }), + } + } + + #[inline(always)] + pub const fn hot(&self) -> SnipeRuleHot { + self.hot + } + + #[inline(always)] + pub fn cold_arc(&self) -> Arc { + Arc::clone(&self.cold) + } + + #[inline(always)] + pub fn address(&self) -> &RuleAddress { + &self.cold.address + } + + #[inline(always)] + pub const fn snipe_height(&self) -> RuleSolAmount { + self.hot.snipe_height + } + + #[inline(always)] + pub const fn jito_tip(&self) -> RuleSolAmount { + self.hot.jito_tip + } + + #[inline(always)] + pub const fn slippage(&self) -> RuleSlippageBps { + self.hot.slippage + } + + pub fn as_log_line(&self, label: &str) -> String { + format!( + "{} > {} \\n\t\t\tSnipe height: {} SOL \\n\t\t\tJito tip: {} SOL \\n\t\t\tSlippage: {} %", + label, + self.address(), + self.snipe_height().as_sol_string(), + self.jito_tip().as_sol_string(), + self.slippage().as_pct_string(), + ) + } +} + +#[cfg(test)] +mod tests { + use super::SnipeRule; + use crate::domain::value_objects::{ + RuleAddress, RuleSlippageBps, RuleSolAmount, sol_amount::Lamports, + }; + + fn build_rule() -> Option { + let address = RuleAddress::try_from("So11111111111111111111111111111111111111112").ok()?; + let slippage = RuleSlippageBps::from_pct_str("1.5").ok()?; + Some(SnipeRule::new( + address, + RuleSolAmount::new(Lamports::new(1_000_000_000)), + RuleSolAmount::new(Lamports::new(100_000_000)), + slippage, + )) + } + + #[test] + fn stores_hot_and_cold_parts() { + let rule = build_rule(); + assert!(rule.is_some()); + + if let Some(rule) = rule { + assert_eq!( + rule.address().as_str(), + "So11111111111111111111111111111111111111112" + ); + assert_eq!(rule.snipe_height().as_lamports().as_u64(), 1_000_000_000); + assert_eq!(rule.jito_tip().as_lamports().as_u64(), 100_000_000); + assert_eq!(rule.slippage().as_bps(), 150); + } + } + + #[test] + fn formats_log_line() { + let rule = build_rule(); + assert!(rule.is_some()); + + if let Some(rule) = rule { + let line = rule.as_log_line("Token address"); + assert!(line.contains("Token address")); + assert!(line.contains("Snipe height: 1 SOL")); + assert!(line.contains("Jito tip: 0.1 SOL")); + assert!(line.contains("Slippage: 1.50 %")); + } + } +} diff --git a/src/domain/events/mod.rs b/src/domain/events/mod.rs new file mode 100644 index 0000000..3e4aa00 --- /dev/null +++ b/src/domain/events/mod.rs @@ -0,0 +1,128 @@ +use std::time::{SystemTime, UNIX_EPOCH}; + +const HARDWARE_TIMESTAMP_MAX_SKEW_NS: u64 = 5_000_000_000; + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum IngressSource { + FpgaDma, + KernelBypass, + StandardTcp, +} + +impl IngressSource { + #[inline(always)] + pub const fn as_str(self) -> &'static str { + match self { + Self::FpgaDma => "fpga_dma", + Self::KernelBypass => "kernel_bypass", + Self::StandardTcp => "standard_tcp", + } + } +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct IngressMetadata { + pub source: IngressSource, + pub hardware_timestamp_ns: Option, + pub received_timestamp_ns: u64, + pub normalized_timestamp_ns: u64, +} + +impl IngressMetadata { + #[inline(always)] + pub const fn from_hardware_clock( + source: IngressSource, + hardware_timestamp_ns: Option, + received_timestamp_ns: u64, + ) -> Self { + Self { + source, + hardware_timestamp_ns, + received_timestamp_ns, + normalized_timestamp_ns: normalize_hardware_timestamp_ns( + hardware_timestamp_ns, + received_timestamp_ns, + ), + } + } + + #[inline(always)] + pub const fn from_receive_clock(source: IngressSource, received_timestamp_ns: u64) -> Self { + Self::from_hardware_clock(source, None, received_timestamp_ns) + } +} + +#[derive(Clone, Debug)] +pub struct RawLogEvent { + pub signature: String, + pub logs: Vec, + pub has_error: bool, + pub ingress: IngressMetadata, +} + +#[inline(always)] +pub const fn normalize_hardware_timestamp_ns( + hardware_timestamp_ns: Option, + received_timestamp_ns: u64, +) -> u64 { + match hardware_timestamp_ns { + Some(value) if value != 0 => { + let min = received_timestamp_ns.saturating_sub(HARDWARE_TIMESTAMP_MAX_SKEW_NS); + let max = received_timestamp_ns.saturating_add(HARDWARE_TIMESTAMP_MAX_SKEW_NS); + if value < min || value > max { + received_timestamp_ns + } else { + value + } + } + _ => received_timestamp_ns, + } +} + +#[inline(always)] +pub fn unix_timestamp_now_ns() -> u64 { + let Ok(duration) = SystemTime::now().duration_since(UNIX_EPOCH) else { + return 0; + }; + + u64::try_from(duration.as_nanos()).unwrap_or(u64::MAX) +} + +#[cfg(test)] +mod tests { + use super::{ + IngressMetadata, IngressSource, normalize_hardware_timestamp_ns, unix_timestamp_now_ns, + }; + + #[test] + fn accepts_hardware_timestamp_within_skew_window() { + let receive_ns = 10_000_000_000_u64; + let hardware_ns = receive_ns.saturating_sub(250_000); + + assert_eq!( + normalize_hardware_timestamp_ns(Some(hardware_ns), receive_ns), + hardware_ns + ); + } + + #[test] + fn clamps_outlier_hardware_timestamp_to_receive_clock() { + let receive_ns = 10_000_000_000_u64; + let outlier_ns = receive_ns.saturating_add(10_000_000_000); + + assert_eq!( + normalize_hardware_timestamp_ns(Some(outlier_ns), receive_ns), + receive_ns + ); + } + + #[test] + fn builds_receive_clock_metadata() { + let receive_ns = unix_timestamp_now_ns(); + let metadata = IngressMetadata::from_receive_clock(IngressSource::StandardTcp, receive_ns); + + assert_eq!(metadata.source, IngressSource::StandardTcp); + assert_eq!(metadata.hardware_timestamp_ns, None); + assert_eq!(metadata.normalized_timestamp_ns, receive_ns); + } +} diff --git a/src/domain/mod.rs b/src/domain/mod.rs new file mode 100644 index 0000000..64044fd --- /dev/null +++ b/src/domain/mod.rs @@ -0,0 +1,8 @@ +pub mod aggregates; +pub mod config; +pub mod entities; +pub mod events; +pub mod services; +pub mod settings; +pub mod specifications; +pub mod value_objects; diff --git a/src/domain/services/mod.rs b/src/domain/services/mod.rs new file mode 100644 index 0000000..f771365 --- /dev/null +++ b/src/domain/services/mod.rs @@ -0,0 +1,3 @@ +pub mod rule_matcher; + +pub use rule_matcher::RuleMatcher; diff --git a/src/domain/services/rule_matcher.rs b/src/domain/services/rule_matcher.rs new file mode 100644 index 0000000..a1f0355 --- /dev/null +++ b/src/domain/services/rule_matcher.rs @@ -0,0 +1,110 @@ +use std::sync::Arc; + +use crate::domain::{ + aggregates::RuleBook, + entities::{SnipeRuleCold, SnipeRuleHot}, + specifications::{DeployerAddressMatchSpecification, MintAddressMatchSpecification}, +}; + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum RuleSource { + Mint, + Deployer, +} + +#[derive(Clone, Debug)] +pub struct MatchedRule { + pub source: RuleSource, + pub hot: SnipeRuleHot, + pub cold: Arc, +} + +pub struct RuleMatcher; + +impl RuleMatcher { + #[inline(always)] + pub fn match_rule( + rule_book: &RuleBook, + token_address: &str, + deployer_address: &str, + ) -> Option { + let mint_specification = MintAddressMatchSpecification::new(token_address); + if let Some(rule) = mint_specification.select(rule_book) { + return Some(MatchedRule { + source: RuleSource::Mint, + hot: rule.hot(), + cold: rule.cold_arc(), + }); + } + + let deployer_specification = DeployerAddressMatchSpecification::new(deployer_address); + deployer_specification + .select(rule_book) + .map(|rule| MatchedRule { + source: RuleSource::Deployer, + hot: rule.hot(), + cold: rule.cold_arc(), + }) + } +} + +#[cfg(test)] +mod tests { + use super::{RuleMatcher, RuleSource}; + use crate::domain::{ + aggregates::RuleBook, + entities::SnipeRule, + value_objects::{RuleAddress, RuleSlippageBps, RuleSolAmount, sol_amount::Lamports}, + }; + + fn build_rule(address: &str) -> Option { + let address = RuleAddress::try_from(address).ok()?; + let slippage = RuleSlippageBps::from_pct_str("1").ok()?; + Some(SnipeRule::new( + address, + RuleSolAmount::new(Lamports::new(1_000_000_000)), + RuleSolAmount::new(Lamports::new(100_000_000)), + slippage, + )) + } + + #[test] + fn prioritizes_mint_match_over_deployer_match() { + let mint = build_rule("So11111111111111111111111111111111111111112"); + let deployer = build_rule("11111111111111111111111111111111"); + assert!(mint.is_some()); + assert!(deployer.is_some()); + + if let (Some(mint), Some(deployer)) = (mint, deployer) { + let book = RuleBook::new(vec![mint], vec![deployer]); + let matched = RuleMatcher::match_rule( + &book, + "So11111111111111111111111111111111111111112", + "11111111111111111111111111111111", + ); + assert!(matched.is_some()); + if let Some(matched) = matched { + assert_eq!(matched.source, RuleSource::Mint); + } + } + } + + #[test] + fn falls_back_to_deployer_match() { + let deployer = build_rule("11111111111111111111111111111111"); + assert!(deployer.is_some()); + + if let Some(deployer) = deployer { + let book = RuleBook::new(Vec::new(), vec![deployer]); + let matched = RuleMatcher::match_rule( + &book, + "So11111111111111111111111111111111111111112", + "11111111111111111111111111111111", + ); + assert!(matched.is_some()); + if let Some(matched) = matched { + assert_eq!(matched.source, RuleSource::Deployer); + } + } + } +} diff --git a/src/domain/settings.rs b/src/domain/settings.rs new file mode 100644 index 0000000..44d7b36 --- /dev/null +++ b/src/domain/settings.rs @@ -0,0 +1,434 @@ +use std::env; + +use crate::domain::{ + config::{SniperConfigFile, load_sniper_config_file}, + value_objects::{ + KernelBypassEngine, NonEmptyText, PriorityFeesMicrolamports, ReplayBurstSize, + ReplayEventCount, TxSubmissionMode, + }, +}; + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum NetworkStackMode { + Fpga, + KernelBypass, + StandardTcp, +} + +impl NetworkStackMode { + #[inline(always)] + pub const fn as_str(self) -> &'static str { + match self { + Self::Fpga => "fpga", + Self::KernelBypass => "kernel_bypass", + Self::StandardTcp => "standard_tcp", + } + } +} + +#[derive(Clone, Debug)] +pub struct RuntimeSettings { + pub config_path: String, + pub priority_fees: PriorityFeesMicrolamports, + pub keypair_path: String, + pub tx_submission_mode: TxSubmissionMode, + pub jito_url: String, + pub rpc_url: String, + pub wss_url: NonEmptyText, + pub kernel_tcp_bypass_enabled: bool, + pub kernel_tcp_bypass_engine: KernelBypassEngine, + pub kernel_bypass_socket_path: NonEmptyText, + pub fpga_enabled: bool, + pub fpga_verbose: bool, + pub fpga_vendor: NonEmptyText, + pub network_stack_mode: NetworkStackMode, + pub run_replay_benchmark: bool, + pub replay_event_count: ReplayEventCount, + pub replay_burst_size: ReplayBurstSize, + pub latency_sample_capacity: usize, + pub latency_slo_ns: u64, + pub latency_report_period_secs: u64, + pub telemetry_enabled: bool, +} + +impl RuntimeSettings { + pub fn from_args() -> Result { + let args = env::args().skip(1).collect::>(); + Self::from_cli_args(&args) + } + + pub(crate) fn from_cli_args(args: &[String]) -> Result { + let config_path = arg_value(args, "--config").unwrap_or_else(|| "sniper.toml".to_owned()); + let parsed_config = load_sniper_config_file(&config_path)?; + Self::from_parsed_config(args, config_path, &parsed_config) + } + + fn from_parsed_config( + args: &[String], + config_path: String, + parsed_config: &SniperConfigFile, + ) -> Result { + let runtime = &parsed_config.runtime; + let telemetry = &parsed_config.telemetry; + + let run_replay_benchmark = arg_flag(args, "--replay-benchmark") || runtime.replay_benchmark; + let replay_event_count = ReplayEventCount::new(runtime.replay_event_count) + .map_err(|message| format!("replay_event_count {}", message))?; + let replay_burst_size = ReplayBurstSize::new(runtime.replay_burst_size) + .map_err(|message| format!("replay_burst_size {}", message))?; + + let kernel_tcp_bypass_enabled = runtime.kernel_tcp_bypass; + let kernel_tcp_bypass_engine = KernelBypassEngine::parse(&runtime.kernel_tcp_bypass_engine) + .ok_or_else(|| { + format!( + "Invalid kernel_tcp_bypass_engine '{}'. Supported values: af_xdp, dpdk, openonload, af_xdp_or_dpdk_external", + runtime.kernel_tcp_bypass_engine + ) + })?; + let kernel_bypass_socket_path = + NonEmptyText::try_from(runtime.kernel_bypass_socket_path.clone()) + .map_err(|_error| "kernel_bypass_socket_path must not be empty".to_owned())?; + + let tx_submission_mode = + TxSubmissionMode::parse(&runtime.tx_submission_mode).ok_or_else(|| { + format!( + "Invalid tx_submission_mode '{}'", + runtime.tx_submission_mode + ) + })?; + + let fpga_enabled = arg_flag(args, "--fpga") || runtime.fpga_enabled; + let fpga_verbose = arg_flag(args, "--fpga-verbose") || runtime.fpga_verbose; + let fpga_vendor = NonEmptyText::try_from(runtime.fpga_vendor.clone()) + .map_err(|_error| "fpga_vendor must not be empty".to_owned())?; + + let network_stack_mode = if fpga_enabled { + NetworkStackMode::Fpga + } else if kernel_tcp_bypass_enabled { + NetworkStackMode::KernelBypass + } else { + NetworkStackMode::StandardTcp + }; + + if !run_replay_benchmark { + if runtime.keypair_path.trim().is_empty() { + return Err("Missing keypair_path in runtime config".to_owned()); + } + if runtime.rpc_url.trim().is_empty() { + return Err("Missing rpc_url in runtime config".to_owned()); + } + if runtime.wss_url.trim().is_empty() { + return Err("Missing wss_url in runtime config".to_owned()); + } + } + + let keypair_path = runtime.keypair_path.clone(); + let rpc_url = runtime.rpc_url.clone(); + let jito_url = if run_replay_benchmark { + runtime.jito_url.clone().unwrap_or_default() + } else if tx_submission_mode == TxSubmissionMode::Jito { + runtime + .jito_url + .clone() + .filter(|value| !value.trim().is_empty()) + .ok_or_else(|| "Missing jito_url for jito submission mode".to_owned())? + } else { + runtime.jito_url.clone().unwrap_or_else(|| rpc_url.clone()) + }; + + let wss_url_raw = if run_replay_benchmark && runtime.wss_url.trim().is_empty() { + "wss://localhost".to_owned() + } else { + runtime.wss_url.clone() + }; + let wss_url = NonEmptyText::try_from(wss_url_raw) + .map_err(|_error| "wss_url must not be empty".to_owned())?; + + if telemetry.enabled && telemetry.sample_capacity == 0 { + return Err( + "telemetry.sample_capacity must be greater than 0 when telemetry.enabled=true" + .to_owned(), + ); + } + if telemetry.enabled && telemetry.report_period_secs == 0 { + return Err( + "telemetry.report_period_secs must be greater than 0 when telemetry.enabled=true" + .to_owned(), + ); + } + + Ok(Self { + config_path, + priority_fees: PriorityFeesMicrolamports::new(runtime.priority_fees), + keypair_path, + tx_submission_mode, + jito_url, + rpc_url, + wss_url, + kernel_tcp_bypass_enabled, + kernel_tcp_bypass_engine, + kernel_bypass_socket_path, + fpga_enabled, + fpga_verbose, + fpga_vendor, + network_stack_mode, + run_replay_benchmark, + replay_event_count, + replay_burst_size, + latency_sample_capacity: telemetry.sample_capacity, + latency_slo_ns: telemetry.slo_ns, + latency_report_period_secs: telemetry.report_period_secs, + telemetry_enabled: telemetry.enabled, + }) + } +} + +fn arg_flag(args: &[String], flag: &str) -> bool { + args.iter().any(|arg| arg == flag) +} + +fn arg_value(args: &[String], flag: &str) -> Option { + args.iter() + .position(|arg| arg == flag) + .and_then(|index| args.get(index.saturating_add(1))) + .cloned() +} + +#[cfg(test)] +mod tests { + use super::{NetworkStackMode, RuntimeSettings}; + use crate::domain::{ + config::{SniperConfigFile, parse_sniper_config_toml}, + value_objects::{KernelBypassEngine, TxSubmissionMode}, + }; + + fn minimal_config() -> Result { + parse_sniper_config_toml( + r#" +[runtime] +keypair_path = "keypair.json" +rpc_url = "https://rpc.example" +wss_url = "wss://wss.example" +priority_fees = 1000 +tx_submission_mode = "jito" +jito_url = "https://jito.example" +kernel_tcp_bypass = true +kernel_tcp_bypass_engine = "af_xdp_or_dpdk_external" +fpga_enabled = false +fpga_verbose = false +fpga_vendor = "generic" +replay_benchmark = false +replay_event_count = 50000 +replay_burst_size = 512 + +[telemetry] +enabled = true +sample_capacity = 4096 +slo_ns = 1000000 +report_period_secs = 15 +"#, + ) + } + + #[test] + fn defaults_to_kernel_bypass_mode() { + let config = minimal_config(); + assert!(config.is_ok()); + if let Ok(config) = config { + let settings = + RuntimeSettings::from_parsed_config(&Vec::new(), "sniper.toml".to_owned(), &config); + assert!(settings.is_ok()); + if let Ok(settings) = settings { + assert_eq!(settings.network_stack_mode, NetworkStackMode::KernelBypass); + assert_eq!( + settings.kernel_tcp_bypass_engine, + KernelBypassEngine::AfXdpOrDpdkExternal + ); + assert_eq!(settings.tx_submission_mode, TxSubmissionMode::Jito); + } + } + } + + #[test] + fn enables_fpga_mode_from_flag() { + let config = minimal_config(); + assert!(config.is_ok()); + if let Ok(config) = config { + let settings = RuntimeSettings::from_parsed_config( + &["--fpga".to_owned()], + "sniper.toml".to_owned(), + &config, + ); + assert!(settings.is_ok()); + if let Ok(settings) = settings { + assert_eq!(settings.network_stack_mode, NetworkStackMode::Fpga); + assert!(settings.fpga_enabled); + } + } + } + + #[test] + fn supports_standard_tcp_mode_when_bypass_disabled() { + let config = parse_sniper_config_toml( + r#" +[runtime] +keypair_path = "keypair.json" +rpc_url = "https://rpc.example" +wss_url = "wss://wss.example" +priority_fees = 1000 +tx_submission_mode = "jito" +jito_url = "https://jito.example" +kernel_tcp_bypass = false +kernel_tcp_bypass_engine = "af_xdp" +fpga_enabled = false +fpga_verbose = false +fpga_vendor = "generic" +replay_benchmark = false +replay_event_count = 50000 +replay_burst_size = 512 +"#, + ); + assert!(config.is_ok()); + if let Ok(config) = config { + let settings = + RuntimeSettings::from_parsed_config(&Vec::new(), "sniper.toml".to_owned(), &config); + assert!(settings.is_ok()); + if let Ok(settings) = settings { + assert_eq!(settings.network_stack_mode, NetworkStackMode::StandardTcp); + } + } + } + + #[test] + fn direct_mode_does_not_require_jito_url() { + let config = parse_sniper_config_toml( + r#" +[runtime] +keypair_path = "keypair.json" +rpc_url = "https://rpc.example" +wss_url = "wss://wss.example" +priority_fees = 1000 +tx_submission_mode = "direct" +kernel_tcp_bypass = true +kernel_tcp_bypass_engine = "af_xdp" +fpga_enabled = false +fpga_verbose = false +fpga_vendor = "generic" +replay_benchmark = false +replay_event_count = 50000 +replay_burst_size = 512 +"#, + ); + assert!(config.is_ok()); + if let Ok(config) = config { + let settings = + RuntimeSettings::from_parsed_config(&Vec::new(), "sniper.toml".to_owned(), &config); + assert!(settings.is_ok()); + if let Ok(settings) = settings { + assert_eq!(settings.tx_submission_mode, TxSubmissionMode::Direct); + assert_eq!(settings.jito_url, "https://rpc.example"); + } + } + } + + #[test] + fn accepts_openonload_kernel_engine() { + let config = parse_sniper_config_toml( + r#" +[runtime] +keypair_path = "keypair.json" +rpc_url = "https://rpc.example" +wss_url = "wss://wss.example" +priority_fees = 1000 +tx_submission_mode = "direct" +kernel_tcp_bypass = true +kernel_tcp_bypass_engine = "openonload" +fpga_enabled = false +fpga_verbose = false +fpga_vendor = "generic" +replay_benchmark = false +replay_event_count = 50000 +replay_burst_size = 512 +"#, + ); + assert!(config.is_ok()); + if let Ok(config) = config { + let settings = + RuntimeSettings::from_parsed_config(&Vec::new(), "sniper.toml".to_owned(), &config); + assert!(settings.is_ok()); + if let Ok(settings) = settings { + assert_eq!( + settings.kernel_tcp_bypass_engine, + KernelBypassEngine::OpenOnload + ); + assert_eq!(settings.network_stack_mode, NetworkStackMode::KernelBypass); + } + } + } + + #[test] + fn rejects_unknown_tx_submission_mode() { + let config = parse_sniper_config_toml( + r#" +[runtime] +keypair_path = "keypair.json" +rpc_url = "https://rpc.example" +wss_url = "wss://wss.example" +priority_fees = 1000 +tx_submission_mode = "unknown" +jito_url = "https://jito.example" +kernel_tcp_bypass = true +kernel_tcp_bypass_engine = "af_xdp" +fpga_enabled = false +fpga_verbose = false +fpga_vendor = "generic" +replay_benchmark = false +replay_event_count = 50000 +replay_burst_size = 512 +"#, + ); + assert!(config.is_ok()); + if let Ok(config) = config { + let settings = + RuntimeSettings::from_parsed_config(&Vec::new(), "sniper.toml".to_owned(), &config); + assert!(settings.is_err()); + } + } + + #[test] + fn disabled_telemetry_accepts_zero_capacity_and_report_period() { + let config = parse_sniper_config_toml( + r#" +[runtime] +keypair_path = "keypair.json" +rpc_url = "https://rpc.example" +wss_url = "wss://wss.example" +priority_fees = 1000 +tx_submission_mode = "direct" +kernel_tcp_bypass = true +kernel_tcp_bypass_engine = "af_xdp" +fpga_enabled = false +fpga_verbose = false +fpga_vendor = "generic" +replay_benchmark = false +replay_event_count = 50000 +replay_burst_size = 512 + +[telemetry] +enabled = false +sample_capacity = 0 +slo_ns = 1000000 +report_period_secs = 0 +"#, + ); + assert!(config.is_ok()); + if let Ok(config) = config { + let settings = + RuntimeSettings::from_parsed_config(&Vec::new(), "sniper.toml".to_owned(), &config); + assert!(settings.is_ok()); + if let Ok(settings) = settings { + assert!(!settings.telemetry_enabled); + } + } + } +} diff --git a/src/domain/specifications/mod.rs b/src/domain/specifications/mod.rs new file mode 100644 index 0000000..fc0b202 --- /dev/null +++ b/src/domain/specifications/mod.rs @@ -0,0 +1,3 @@ +pub mod rule_matching; + +pub use rule_matching::{DeployerAddressMatchSpecification, MintAddressMatchSpecification}; diff --git a/src/domain/specifications/rule_matching.rs b/src/domain/specifications/rule_matching.rs new file mode 100644 index 0000000..953c6b2 --- /dev/null +++ b/src/domain/specifications/rule_matching.rs @@ -0,0 +1,84 @@ +use crate::domain::{aggregates::RuleBook, entities::SnipeRule}; + +#[derive(Clone, Copy, Debug)] +pub struct MintAddressMatchSpecification<'address> { + token_address: &'address str, +} + +impl<'address> MintAddressMatchSpecification<'address> { + #[inline(always)] + pub const fn new(token_address: &'address str) -> Self { + Self { token_address } + } + + #[inline(always)] + pub fn select(self, rule_book: &RuleBook) -> Option<&SnipeRule> { + rule_book.mint_rule(self.token_address) + } +} + +#[derive(Clone, Copy, Debug)] +pub struct DeployerAddressMatchSpecification<'address> { + deployer_address: &'address str, +} + +impl<'address> DeployerAddressMatchSpecification<'address> { + #[inline(always)] + pub const fn new(deployer_address: &'address str) -> Self { + Self { deployer_address } + } + + #[inline(always)] + pub fn select(self, rule_book: &RuleBook) -> Option<&SnipeRule> { + rule_book.deployer_rule(self.deployer_address) + } +} + +#[cfg(test)] +mod tests { + use super::{DeployerAddressMatchSpecification, MintAddressMatchSpecification}; + use crate::domain::{ + aggregates::RuleBook, + entities::SnipeRule, + value_objects::{RuleAddress, RuleSlippageBps, RuleSolAmount, sol_amount::Lamports}, + }; + + fn build_rule(address: &str) -> Option { + let address = RuleAddress::try_from(address).ok()?; + let slippage = RuleSlippageBps::from_pct_str("1").ok()?; + Some(SnipeRule::new( + address, + RuleSolAmount::new(Lamports::new(1_000_000_000)), + RuleSolAmount::new(Lamports::new(100_000_000)), + slippage, + )) + } + + #[test] + fn selects_mint_rule_by_address() { + let mint_rule = build_rule("So11111111111111111111111111111111111111112"); + assert!(mint_rule.is_some()); + + if let Some(mint_rule) = mint_rule { + let book = RuleBook::new(vec![mint_rule], Vec::new()); + let selected = + MintAddressMatchSpecification::new("So11111111111111111111111111111111111111112") + .select(&book); + assert!(selected.is_some()); + } + } + + #[test] + fn selects_deployer_rule_by_address() { + let deployer_rule = build_rule("11111111111111111111111111111111"); + assert!(deployer_rule.is_some()); + + if let Some(deployer_rule) = deployer_rule { + let book = RuleBook::new(Vec::new(), vec![deployer_rule]); + let selected = + DeployerAddressMatchSpecification::new("11111111111111111111111111111111") + .select(&book); + assert!(selected.is_some()); + } + } +} diff --git a/src/domain/value_objects/mod.rs b/src/domain/value_objects/mod.rs new file mode 100644 index 0000000..2f7c7c4 --- /dev/null +++ b/src/domain/value_objects/mod.rs @@ -0,0 +1,9 @@ +pub mod rule_primitives; +pub mod runtime; +pub mod sol_amount; + +pub use rule_primitives::{RuleAddress, RuleSlippageBps, RuleSolAmount}; +pub use runtime::{ + KernelBypassEngine, NonEmptyText, PriorityFeesMicrolamports, ReplayBurstSize, ReplayEventCount, + TxSubmissionMode, +}; diff --git a/src/domain/value_objects/rule_primitives.rs b/src/domain/value_objects/rule_primitives.rs new file mode 100644 index 0000000..eb55b20 --- /dev/null +++ b/src/domain/value_objects/rule_primitives.rs @@ -0,0 +1,180 @@ +use std::{ + borrow::Borrow, + fmt::{Display, Formatter}, + sync::Arc, +}; + +use crate::domain::value_objects::sol_amount::Lamports; + +#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub struct RuleAddress(Arc); + +impl RuleAddress { + pub fn new(value: impl Into>) -> Result { + let value = value.into(); + + if value.trim().is_empty() { + return Err("rule address must not be empty"); + } + + Ok(Self(value)) + } + + #[inline(always)] + pub fn as_str(&self) -> &str { + &self.0 + } +} + +impl AsRef for RuleAddress { + #[inline(always)] + fn as_ref(&self) -> &str { + self.as_str() + } +} + +impl Borrow for RuleAddress { + #[inline(always)] + fn borrow(&self) -> &str { + self.as_str() + } +} + +impl Display for RuleAddress { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.write_str(self.as_str()) + } +} + +impl TryFrom for RuleAddress { + type Error = &'static str; + + fn try_from(value: String) -> Result { + RuleAddress::new(Arc::::from(value)) + } +} + +impl TryFrom<&str> for RuleAddress { + type Error = &'static str; + + fn try_from(value: &str) -> Result { + RuleAddress::new(Arc::::from(value.to_owned())) + } +} + +#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] +pub struct RuleSlippageBps(u16); + +impl RuleSlippageBps { + pub const MAX_BPS: u16 = 10_000; + + pub fn from_pct_str(value: &str) -> Result { + let value = value.trim(); + if value.is_empty() { + return Err("slippage must not be empty"); + } + + let (whole_raw, fractional_raw) = value.split_once('.').unwrap_or((value, "0")); + if fractional_raw.len() > 4 { + return Err("slippage supports up to 4 decimal places"); + } + + let whole_part = whole_raw + .parse::() + .map_err(|_parse_error| "invalid slippage value")?; + + if !fractional_raw + .chars() + .all(|character| character.is_ascii_digit()) + { + return Err("invalid slippage value"); + } + + let mut fractional_scaled = fractional_raw.to_owned(); + while fractional_scaled.len() < 4 { + fractional_scaled.push('0'); + } + + let fractional_part = fractional_scaled + .parse::() + .map_err(|_parse_error| "invalid slippage value")?; + + let pct_scaled_4 = whole_part + .checked_mul(10_000) + .and_then(|scaled_value| scaled_value.checked_add(fractional_part)) + .ok_or("slippage value overflow")?; + + let bps = pct_scaled_4 + .checked_div(100) + .ok_or("invalid slippage value")?; + + if bps > u64::from(Self::MAX_BPS) { + return Err("slippage must be between 0 and 100"); + } + + let bps = u16::try_from(bps).map_err(|_conversion_error| "slippage value overflow")?; + Ok(Self(bps)) + } + + #[inline(always)] + pub const fn as_bps(self) -> u16 { + self.0 + } + + pub fn as_pct_string(self) -> String { + let whole = self.0 / 100; + let fractional = self.0 % 100; + format!("{whole}.{fractional:02}") + } +} + +#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] +pub struct RuleSolAmount(Lamports); + +impl RuleSolAmount { + #[inline(always)] + pub const fn new(lamports: Lamports) -> Self { + Self(lamports) + } + + #[inline(always)] + pub const fn as_lamports(self) -> Lamports { + self.0 + } + + #[inline(always)] + pub fn as_sol_string(self) -> String { + self.0.as_sol_string() + } +} + +#[cfg(test)] +mod tests { + use super::{RuleAddress, RuleSlippageBps}; + + #[test] + fn creates_non_empty_rule_address() { + let address = RuleAddress::try_from("So11111111111111111111111111111111111111112"); + assert!(address.is_ok()); + + let empty = RuleAddress::try_from(" "); + assert!(empty.is_err()); + } + + #[test] + fn parses_slippage_from_percent_without_float_math() { + let parsed = RuleSlippageBps::from_pct_str("1.25"); + assert!(parsed.is_ok()); + + if let Ok(value) = parsed { + assert_eq!(value.as_bps(), 125); + assert_eq!(value.as_pct_string(), "1.25"); + } + } + + #[test] + fn rejects_slippage_outside_bounds() { + assert!(RuleSlippageBps::from_pct_str("100.01").is_err()); + assert!(RuleSlippageBps::from_pct_str("abc").is_err()); + } +} diff --git a/src/domain/value_objects/runtime.rs b/src/domain/value_objects/runtime.rs new file mode 100644 index 0000000..b268b2e --- /dev/null +++ b/src/domain/value_objects/runtime.rs @@ -0,0 +1,250 @@ +use std::{ + borrow::Borrow, + fmt::{Display, Formatter}, + num::NonZeroUsize, + sync::Arc, +}; + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum KernelBypassEngine { + AfXdp, + Dpdk, + OpenOnload, + AfXdpOrDpdkExternal, +} + +impl KernelBypassEngine { + pub fn parse(value: &str) -> Option { + let normalized = value.trim().to_ascii_lowercase(); + match normalized.as_str() { + "af_xdp" => Some(Self::AfXdp), + "dpdk" => Some(Self::Dpdk), + "openonload" | "onload" => Some(Self::OpenOnload), + "af_xdp_or_dpdk_external" => Some(Self::AfXdpOrDpdkExternal), + _ => None, + } + } + + #[inline(always)] + pub const fn as_str(self) -> &'static str { + match self { + Self::AfXdp => "af_xdp", + Self::Dpdk => "dpdk", + Self::OpenOnload => "openonload", + Self::AfXdpOrDpdkExternal => "af_xdp_or_dpdk_external", + } + } +} + +impl Display for KernelBypassEngine { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.write_str(self.as_str()) + } +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum TxSubmissionMode { + Jito, + Direct, +} + +impl TxSubmissionMode { + pub fn parse(value: &str) -> Option { + let normalized = value.trim().to_ascii_lowercase(); + match normalized.as_str() { + "jito" => Some(Self::Jito), + "direct" => Some(Self::Direct), + _ => None, + } + } + + #[inline(always)] + pub const fn as_str(self) -> &'static str { + match self { + Self::Jito => "jito", + Self::Direct => "direct", + } + } +} + +impl Display for TxSubmissionMode { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.write_str(self.as_str()) + } +} + +#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] +pub struct PriorityFeesMicrolamports(u64); + +impl PriorityFeesMicrolamports { + #[inline(always)] + pub const fn new(value: u64) -> Self { + Self(value) + } + + #[inline(always)] + pub const fn as_u64(self) -> u64 { + self.0 + } +} + +#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] +pub struct ReplayEventCount(NonZeroUsize); + +impl ReplayEventCount { + pub fn new(value: usize) -> Result { + NonZeroUsize::new(value) + .map(Self) + .ok_or("replay event count must be greater than 0") + } + + #[inline(always)] + pub const fn get(self) -> usize { + self.0.get() + } +} + +#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] +pub struct ReplayBurstSize(NonZeroUsize); + +impl ReplayBurstSize { + pub fn new(value: usize) -> Result { + NonZeroUsize::new(value) + .map(Self) + .ok_or("replay burst size must be greater than 0") + } + + #[inline(always)] + pub const fn get(self) -> usize { + self.0.get() + } +} + +#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub struct NonEmptyText(Arc); + +impl NonEmptyText { + pub fn new(value: impl Into>) -> Result { + let value = value.into(); + if value.trim().is_empty() { + return Err("text value must not be empty"); + } + + Ok(Self(value)) + } + + #[inline(always)] + pub fn as_str(&self) -> &str { + &self.0 + } +} + +impl AsRef for NonEmptyText { + #[inline(always)] + fn as_ref(&self) -> &str { + self.as_str() + } +} + +impl Borrow for NonEmptyText { + #[inline(always)] + fn borrow(&self) -> &str { + self.as_str() + } +} + +impl Display for NonEmptyText { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.write_str(self.as_str()) + } +} + +impl TryFrom for NonEmptyText { + type Error = &'static str; + + fn try_from(value: String) -> Result { + Self::new(Arc::::from(value)) + } +} + +impl TryFrom<&str> for NonEmptyText { + type Error = &'static str; + + fn try_from(value: &str) -> Result { + Self::new(Arc::::from(value.to_owned())) + } +} + +#[cfg(test)] +mod tests { + use super::{ + KernelBypassEngine, NonEmptyText, PriorityFeesMicrolamports, ReplayBurstSize, + ReplayEventCount, TxSubmissionMode, + }; + + #[test] + fn parses_supported_kernel_bypass_engines() { + assert_eq!( + KernelBypassEngine::parse("af_xdp"), + Some(KernelBypassEngine::AfXdp) + ); + assert_eq!( + KernelBypassEngine::parse("DPDK"), + Some(KernelBypassEngine::Dpdk) + ); + assert_eq!( + KernelBypassEngine::parse("af_xdp_or_dpdk_external"), + Some(KernelBypassEngine::AfXdpOrDpdkExternal) + ); + assert_eq!( + KernelBypassEngine::parse("openonload"), + Some(KernelBypassEngine::OpenOnload) + ); + assert_eq!( + KernelBypassEngine::parse("ONLOAD"), + Some(KernelBypassEngine::OpenOnload) + ); + } + + #[test] + fn rejects_invalid_kernel_bypass_engine() { + assert_eq!(KernelBypassEngine::parse("invalid"), None); + } + + #[test] + fn parses_tx_submission_mode() { + assert_eq!( + TxSubmissionMode::parse("jito"), + Some(TxSubmissionMode::Jito) + ); + assert_eq!( + TxSubmissionMode::parse("DIRECT"), + Some(TxSubmissionMode::Direct) + ); + } + + #[test] + fn rejects_invalid_tx_submission_mode() { + assert_eq!(TxSubmissionMode::parse("invalid"), None); + } + + #[test] + fn requires_non_empty_text() { + assert!(NonEmptyText::try_from("vendor".to_owned()).is_ok()); + assert!(NonEmptyText::try_from(" ".to_owned()).is_err()); + } + + #[test] + fn keeps_priority_fee_scalar() { + let value = PriorityFeesMicrolamports::new(42); + assert_eq!(value.as_u64(), 42); + } + + #[test] + fn enforces_non_zero_replay_counts() { + assert!(ReplayEventCount::new(1).is_ok()); + assert!(ReplayEventCount::new(0).is_err()); + assert!(ReplayBurstSize::new(1).is_ok()); + assert!(ReplayBurstSize::new(0).is_err()); + } +} diff --git a/src/domain/value_objects/sol_amount.rs b/src/domain/value_objects/sol_amount.rs new file mode 100644 index 0000000..ced62c0 --- /dev/null +++ b/src/domain/value_objects/sol_amount.rs @@ -0,0 +1,158 @@ +const LAMPORTS_PER_SOL: u64 = 1_000_000_000; + +#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)] +pub struct Lamports(u64); + +impl Lamports { + #[inline(always)] + pub const fn new(value: u64) -> Self { + Self(value) + } + + #[inline(always)] + pub const fn as_u64(self) -> u64 { + self.0 + } + + #[inline(always)] + pub fn as_sol_string(self) -> String { + let whole = self.0 / LAMPORTS_PER_SOL; + let fractional = self.0 % LAMPORTS_PER_SOL; + + if fractional == 0 { + return whole.to_string(); + } + + let mut fractional_string = format!("{fractional:09}"); + while fractional_string.ends_with('0') { + fractional_string.pop(); + } + + format!("{whole}.{fractional_string}") + } +} + +pub fn parse_positive_sol_str_to_lamports(sol: &str) -> Option { + let lamports = parse_sol_str_to_lamports(sol.trim())?; + if lamports == 0 { + return None; + } + + Some(Lamports::new(lamports)) +} + +fn parse_sol_str_to_lamports(sol: &str) -> Option { + if sol.is_empty() || sol.starts_with('-') { + return None; + } + + let (whole_raw, fractional_raw) = match sol.split_once('.') { + Some((whole, fractional)) if !fractional.contains('.') => (whole, fractional), + Some(_) => return None, + None => (sol, ""), + }; + + if whole_raw.is_empty() && fractional_raw.is_empty() { + return None; + } + + if !whole_raw.is_empty() + && !whole_raw + .chars() + .all(|character| character.is_ascii_digit()) + { + return None; + } + + if !fractional_raw.is_empty() + && !fractional_raw + .chars() + .all(|character| character.is_ascii_digit()) + { + return None; + } + + if fractional_raw.len() > 9 { + return None; + } + + let whole = if whole_raw.is_empty() { + 0_u64 + } else { + parse_ascii_u64(whole_raw)? + }; + + let mut fractional = if fractional_raw.is_empty() { + 0_u64 + } else { + parse_ascii_u64(fractional_raw)? + }; + + for _ in fractional_raw.len()..9 { + fractional = fractional.checked_mul(10)?; + } + + whole + .checked_mul(LAMPORTS_PER_SOL) + .and_then(|whole_lamports| whole_lamports.checked_add(fractional)) +} + +fn parse_ascii_u64(value: &str) -> Option { + if value.is_empty() { + return None; + } + + let mut parsed = 0_u64; + for byte in value.bytes() { + if !byte.is_ascii_digit() { + return None; + } + + parsed = parsed + .checked_mul(10)? + .checked_add(u64::from(byte.saturating_sub(b'0')))?; + } + + Some(parsed) +} + +#[cfg(test)] +mod tests { + use super::{Lamports, parse_positive_sol_str_to_lamports}; + + #[test] + fn parses_fixed_point_sol_amounts() { + assert_eq!( + parse_positive_sol_str_to_lamports("1").map(Lamports::as_u64), + Some(1_000_000_000) + ); + assert_eq!( + parse_positive_sol_str_to_lamports("1.23").map(Lamports::as_u64), + Some(1_230_000_000) + ); + assert_eq!( + parse_positive_sol_str_to_lamports(".5").map(Lamports::as_u64), + Some(500_000_000) + ); + assert_eq!( + parse_positive_sol_str_to_lamports("0.000000001").map(Lamports::as_u64), + Some(1) + ); + } + + #[test] + fn rejects_invalid_or_non_positive_values() { + assert_eq!(parse_positive_sol_str_to_lamports("0"), None); + assert_eq!(parse_positive_sol_str_to_lamports("0.000000000"), None); + assert_eq!(parse_positive_sol_str_to_lamports("1.0000000001"), None); + assert_eq!(parse_positive_sol_str_to_lamports("abc"), None); + assert_eq!(parse_positive_sol_str_to_lamports("-1"), None); + } + + #[test] + fn formats_sol_strings_without_float_drift() { + assert_eq!(Lamports::new(1_000_000_000).as_sol_string(), "1"); + assert_eq!(Lamports::new(1_230_000_000).as_sol_string(), "1.23"); + assert_eq!(Lamports::new(1).as_sol_string(), "0.000000001"); + } +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..29ebc57 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,9 @@ +#![allow(clippy::missing_errors_doc, clippy::must_use_candidate)] + +pub mod adapters; +pub mod app; +pub mod domain; +pub mod ports; +pub mod slices; + +pub const MAX_RETRIES: usize = 1_000; diff --git a/src/main.rs b/src/main.rs index 6fe81aa..dce4aa5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,952 +1,4 @@ -mod raydium; -mod utils; - -use chrono::{Local, TimeZone}; -use colored::Colorize; -use solana_account_decoder::UiAccountEncoding; -use solana_sdk::{commitment_config::CommitmentConfig, compute_budget::ComputeBudgetInstruction, instruction::{AccountMeta, Instruction}, native_token::{lamports_to_sol, sol_to_lamports}, pubkey::Pubkey, signature::{Keypair, Signature}, signer::Signer, system_instruction::transfer, transaction::Transaction}; -use solana_client::{nonblocking::rpc_client::RpcClient, rpc_config::{RpcAccountInfoConfig, RpcSendTransactionConfig, RpcTransactionConfig, RpcTransactionLogsConfig, RpcTransactionLogsFilter}}; -use solana_transaction_status::{EncodedTransaction, UiInstruction, UiMessage, UiParsedInstruction, UiTransactionEncoding}; -use spl_associated_token_account::{get_associated_token_address, get_associated_token_address_with_program_id, instruction::{create_associated_token_account, create_associated_token_account_idempotent}}; -use spl_token::instruction::{close_account, sync_native}; -use tokio::{fs::{self, File}, io::AsyncReadExt, sync::Mutex, time}; -use utils::{get_data_from_logs_by_regex, read_mints_or_deployers_from_file, report_changes}; -use std::{env, str::FromStr, sync::Arc, time::Duration}; -use dotenv::dotenv; -use log::{Level, LevelFilter}; -use solana_client::pubsub_client::PubsubClient; -use crate::raydium::*; - -const MAX_RETRIES: usize = 1_000; - #[tokio::main] async fn main() { - let log_level = env::var("RUST_LOG").unwrap_or_else(|_| "info".to_string()); - - let level_filter = match log_level.to_lowercase().as_str() { - "trace" => LevelFilter::Trace, - "debug" => LevelFilter::Debug, - "info" => LevelFilter::Info, - "warn" => LevelFilter::Warn, - "error" => LevelFilter::Error, - _ => LevelFilter::Info, - }; - - let log_dir = "log"; - fs::create_dir_all(log_dir).await.unwrap(); - - fern::Dispatch::new() - .format(move |out, message, record| { - let timestamp = Local::now().format("%Y-%m-%d %H:%M:%S.%3f"); - - let level = format!("[ {} ]", match record.level() { - Level::Info => "+".green(), - Level::Error => "-".red(), - Level::Warn => "!".yellow(), - Level::Debug => "*".blue(), - Level::Trace => "~".purple(), - }); - - out.finish(format_args!( - "{} {} > {}", - timestamp, - level, - message - )) - }) - .level(level_filter) - .chain(std::io::stdout()) - .chain(fern::log_file(format!("{}/output.ans", log_dir)).unwrap()) - .apply() - .unwrap(); - - dotenv().ok(); - - log::info!("Hyper Sniper"); - - let priority_fees = Arc::new(env::var("PRIORITY_FEES") - .expect("Missing PRIORITY_FEES amount") - .parse::() - .expect("Invalid PRIORITY_FEES amount")); - - let mints: Arc>> = Arc::new(Mutex::new(Vec::new())); - let mints_cloned = mints.clone(); - tokio::spawn(async move { - let mut initial = true; - let mut interval = time::interval(Duration::from_secs(1)); - loop { - interval.tick().await; - match read_mints_or_deployers_from_file("mints.txt", "MINTS", initial).await { - Ok(data) => { - let mut write_guard = mints_cloned.lock().await; - - if write_guard.eq(&data) { - continue; - } - - report_changes(&*write_guard, &data, "MINTS", initial); - - *write_guard = data; - - if initial { - initial = false; - } - }, - Err(e) => eprintln!("Failed to read mints data: {}", e), - } - } - }); - - let deployers: Arc>> = Arc::new(Mutex::new(Vec::new())); - let deployers_cloned = deployers.clone(); - tokio::spawn(async move { - let mut initial = true; - let mut interval = time::interval(Duration::from_secs(1)); - loop { - interval.tick().await; - match read_mints_or_deployers_from_file("deployers.txt", "DEPLOYERS", initial).await { - Ok(data) => { - let mut write_guard = deployers_cloned.lock().await; - - if write_guard.eq(&data) { - continue; - } - - report_changes(&*write_guard, &data, "DEPLOYERS", initial); - - *write_guard = data; - - if initial { - initial = false; - } - }, - Err(e) => eprintln!("Failed to read deployers data: {}", e), - } - } - }); - - let keypair_path = env::var("KEYPAIR_PATH") - .expect("Missing KEYPAIR_PATH"); - let mut keypair_file = File::open(keypair_path) - .await - .expect("Failed to open keypair file"); - let mut contents = String::new(); - keypair_file.read_to_string(&mut contents).await.unwrap(); - let keypair_bytes: Vec = serde_json::from_str(&contents).unwrap(); - let keypair = Arc::new(Keypair::from_bytes(&keypair_bytes).unwrap()); - - let jito_url = Arc::new(env::var("JITO_URL") - .expect("Missing JITO_URL")); - - let rpc_url = env::var("RPC_URL") - .expect("Missing RPC URL or Helius API key"); - let rpc = Arc::new(RpcClient::new(rpc_url.to_string())); - - let mints_lock = mints.lock().await; - - let mints_string = mints_lock.iter() - .map(|(address, snipe_height, jito_tip, slippage)| { - format!("Token address > {} \n\t\t\tSnipe height: {} SOL \n\t\t\tJito tip: {} SOL \n\t\t\tSlippage: {} %", address, snipe_height, jito_tip, slippage) - }) - .collect::>() - .join("\n\t\t"); - - drop(mints_lock); - - let deployers_lock = deployers.lock().await; - - let deployers_string = deployers_lock.iter() - .map(|(address, snipe_height, jito_tip, slippage)| { - format!("Deployer address > {} \n\t\t\tSnipe height: {} SOL \n\t\t\tJito tip: {} SOL \n\t\t\tSlippage: {} %", address, snipe_height, jito_tip, slippage) - }) - .collect::>() - .join("\n\t\t"); - - drop(deployers_lock); - - let balance = lamports_to_sol(rpc.get_balance(&keypair.pubkey()).await.unwrap()); - - log::info!("Settings: \n\tWallet: {}\n\tWallet Balance: {} SOL\n\tPRIORITY_FEES: {} µLamports\n\tMINTS:\n\t\t{}\n\tDEPLOYERS:\n\t\t{}\n\tJITO_URL: {}\n\tRPC_URL: {}\n\tWSS_URL: {}", keypair.pubkey(), balance, priority_fees, mints_string, deployers_string, jito_url, rpc_url, env::var("WSS_URL").expect("Missing websocket url or Helius API key")); - - loop { - let logs_filter = RpcTransactionLogsFilter::All; - let logs_config = RpcTransactionLogsConfig { - commitment: Some(CommitmentConfig::confirmed()) - }; - - let ws = PubsubClient::logs_subscribe( - &env::var("WSS_URL") - .expect("Missing websocket url or Helius API key"), logs_filter, logs_config) - .unwrap(); - - log::info!("Listening for tokens..."); - - while let Ok(response) = ws.1.recv_timeout(Duration::from_secs(30)) { - let jito_url = Arc::clone(&jito_url); - let priority_fees = Arc::clone(&priority_fees); - let mints = Arc::clone(&mints); - let deployers = Arc::clone(&deployers); - let rpc = Arc::clone(&rpc); - let keypair = Arc::clone(&keypair); - - tokio::spawn(async move { - let logs = response.value.logs.clone(); - - if response.value.err.is_some() { - return; - } - - let signature = Signature::from_str(&response.value.signature.as_str()).expect("Invalid signature"); - - if logs.iter().any(|log| log.contains(&RAYDIUM_STANDARD_AMM_PROGRAM_ID.to_string())) - && !logs.iter().any(|log| - log.contains(&"SwapBaseIn".to_string()) - || log.contains(&"SwapBaseOutput".to_string()) - || log.contains(&"CollectProtocolFee".to_string()) - || log.contains(&"Deposit".to_string()) - || log.contains(&"CollectFundFee".to_string()) - || log.contains(&"Burn".to_string()) - ) { - let vault_0_amount_str = get_data_from_logs_by_regex(&logs, r"vault_0_amount:(\d+),"); - let vault_0_amount = vault_0_amount_str.unwrap().as_str().parse::().unwrap(); - - let vault_1_amount_str = get_data_from_logs_by_regex(&logs, r"vault_1_amount:(\d+)"); - let vault_1_amount = vault_1_amount_str.unwrap().as_str().parse::().unwrap(); - - log::debug!("CPMM > vault_0_amount: {}, vault_amount_1: {}", vault_0_amount, vault_1_amount); - - let mut tx_retries = 0; - - let tx = loop { - match rpc.get_transaction_with_config(&signature, RpcTransactionConfig { - commitment: Some(CommitmentConfig::confirmed()), - max_supported_transaction_version: Some(0), - encoding: Some(UiTransactionEncoding::JsonParsed), - }).await { - Ok(tx) => break tx, - Err(e) => { - if !e.to_string().contains("invalid type: null") { - log::error!("CPMM > Error getting transaction: {}", e); - } else { - log::debug!("CPMM > Error getting transaction: {}", e); - } - - tx_retries += 1; - - if tx_retries >= MAX_RETRIES { - log::error!("CPMM > Max retries reached in transaction. Exiting loop."); - return; - } - - tokio::time::sleep(tokio::time::Duration::from_millis(1000)).await - } - } - }; - - log::debug!("CPMM > Pool creation transaction: {:?}", tx); - - let mut accounts: Vec = vec![]; - - match tx.transaction.transaction { - EncodedTransaction::LegacyBinary(_) => return, - EncodedTransaction::Binary(_, _) => return, - EncodedTransaction::Json(tx) => { - match tx.message { - UiMessage::Parsed(message) => { - for ix in message.instructions { - match ix { - UiInstruction::Compiled(_) => return, - UiInstruction::Parsed(ix) => { - match ix { - UiParsedInstruction::Parsed(_) => continue, - UiParsedInstruction::PartiallyDecoded(ix) => { - if ix.program_id == RAYDIUM_STANDARD_AMM_PROGRAM_ID { - accounts = ix.accounts; - - break; - } - }, - } - }, - } - } - }, - UiMessage::Raw(_) => return, - } - }, - EncodedTransaction::Accounts(_) => return, - } - - log::debug!("CPMM > Pool creation accounts: {:?}", accounts); - - if accounts.len() == 0 { - return; - } - - if accounts[4] != WSOL_ADDRESS && accounts[5] != WSOL_ADDRESS { - return; - } - - let token_address = if accounts[4] != WSOL_ADDRESS { - &accounts[4] - } else { - &accounts[5] - }; - let token_program = if accounts[4] != WSOL_ADDRESS { - &accounts[15] - } else { - &accounts[16] - }; - let deployer_address = &accounts[0]; - - let mint_data = { - let mints_lock = mints.lock().await; - mints_lock.iter().find(|(address, _, _, _)| address == token_address).cloned() - }; - let deployer_data = { - let deployers_lock = deployers.lock().await; - deployers_lock.iter().find(|(address, _, _, _)| address == deployer_address).cloned() - }; - - log::debug!("CPMM > {} > Mint data: {:?}, Deployer data: {:?}", token_address, mint_data, deployer_data); - - if mint_data.is_none() && deployer_data.is_none() { - log::debug!("CPMM > {} > Ignoring token", token_address); - return; - } - - let (_, sol, jito_tip, slippage) = if mint_data.is_some() { - mint_data.unwrap() - } else if deployer_data.is_some() { - deployer_data.unwrap() - } else { - return; - }; - - log::debug!("CPMM > {} > Snipe height: {} SOL, Jito tip: {} SOL, Slippage: {} %", token_address, sol, jito_tip, slippage); - - log::info!("CPMM > Found token: {}", token_address); - log::info!("CPMM > {} > Creating transaction", token_address); - - let program_id = Pubkey::from_str(RAYDIUM_STANDARD_AMM_PROGRAM_ID).unwrap(); - let authority = Pubkey::from_str(&accounts[2]).unwrap(); - let amm_config = Pubkey::from_str(&accounts[1]).unwrap(); - let pool_state = Pubkey::from_str(&accounts[3]).unwrap(); - let input_vault = if accounts[4] != WSOL_ADDRESS { - Pubkey::from_str(&accounts[11]).unwrap() - } else { - Pubkey::from_str(&accounts[10]).unwrap() - }; - let output_vault = if accounts[4] != WSOL_ADDRESS { - Pubkey::from_str(&accounts[10]).unwrap() - } else { - Pubkey::from_str(&accounts[11]).unwrap() - }; - let observation_state = Pubkey::from_str(&accounts[13]).unwrap(); - - log::debug!("CPMM > {} > Authority: {}, AMM config: {}, Pool state: {}, Input vault: {}, Output vault: {}, Observation state: {}", token_address, authority, amm_config, pool_state, input_vault, output_vault, observation_state); - - log::info!("CPMM > {} > Requesting pool data", token_address); - - let mut pool_retries = 0; - - let pool = loop { - match rpc.get_account_with_config(&pool_state, RpcAccountInfoConfig { - encoding: Some(UiAccountEncoding::Base64), - commitment: Some(CommitmentConfig::confirmed()), - ..Default::default() - }).await { - Ok(pool) => { - if pool.value.is_none() { - log::debug!("CPMM > {} > Pool not available yet: {}", token_address, pool_state.to_string()); - - pool_retries += 1; - - if pool_retries >= MAX_RETRIES { - log::error!("CPMM > Max retries reached in pool. Exiting loop."); - return; - } - - tokio::time::sleep(tokio::time::Duration::from_millis(1000)).await; - - continue; - } - - break pool - }, - Err(e) => { - if !e.to_string().contains("invalid type: null") { - log::error!("CPMM > Error getting pool data: {}", e); - } else { - log::debug!("CPMM > Error getting pool data: {}", e); - } - - pool_retries += 1; - - if pool_retries >= MAX_RETRIES { - log::error!("CPMM > Max retries reached in pool. Exiting loop."); - return; - } - - tokio::time::sleep(tokio::time::Duration::from_millis(1000)).await - } - } - }; - - log::debug!("CPMM > {} > Pool response: {:?}", token_address, pool); - - let pool_open_time = PoolData::get_open_time(&pool.value.unwrap().data); - - log::debug!("CPMM > {} > Pool open time: {}", token_address, pool_open_time); - - let lamports = sol_to_lamports(sol); - let wsol_pubkey = Pubkey::from_str(WSOL_ADDRESS).unwrap(); - - let user_in_token_account = get_associated_token_address( - &keypair.pubkey(), - &wsol_pubkey - ); - - let user_out_token_account = get_associated_token_address_with_program_id( - &keypair.pubkey(), - &Pubkey::from_str(token_address).unwrap(), - &Pubkey::from_str(token_program).unwrap(), - ); - - let mut instructions = vec![]; - - let compute_unit_ix = ComputeBudgetInstruction::set_compute_unit_limit(120_000); - instructions.push(compute_unit_ix); - let compute_unit_price_ix = ComputeBudgetInstruction::set_compute_unit_price(*priority_fees); - instructions.push(compute_unit_price_ix); - - let create_wsol_account_ix = create_associated_token_account_idempotent( - &keypair.pubkey(), - &keypair.pubkey(), - &Pubkey::from_str(WSOL_ADDRESS).unwrap(), - &Pubkey::from_str(TOKEN_PROGRAM_ID).unwrap() - ); - instructions.push(create_wsol_account_ix); - - let transfer_ix = transfer( - &keypair.pubkey(), - &user_in_token_account, - lamports - ); - let sync_ix = sync_native( - &spl_token::ID, - &user_in_token_account - ).unwrap(); - - instructions.push(transfer_ix); - instructions.push(sync_ix); - - let create_token_account_ix = create_associated_token_account( - &keypair.pubkey(), - &keypair.pubkey(), - &Pubkey::from_str(token_address).unwrap(), - &Pubkey::from_str(&token_program).unwrap() - ); - instructions.push(create_token_account_ix); - - let min_amount_out = if slippage != 0.0 { - let token_price = if accounts[4] != WSOL_ADDRESS { - vault_1_amount / vault_0_amount - } else { - vault_0_amount / vault_1_amount - }; - - let max_amount_out = lamports as f64 / token_price; - - log::debug!("CPMM > Token price: {}, amount max out: {}", token_price, max_amount_out); - - max_amount_out * (1.0 - slippage / 100.0) - } else { - 0.0 - } as u64; - - log::debug!("CPMM > {} > Min amount out: {}", token_address, min_amount_out); - - let mut data = Vec::with_capacity(8 + 8 + 8); - data.extend_from_slice(&STANDARD_AMM_SWAP_BASE_INPUT); - data.extend_from_slice(&lamports.to_le_bytes()); - data.extend_from_slice(&min_amount_out.to_le_bytes()); - - let swap_ix = Instruction::new_with_bytes( - program_id, - &data, - vec![ - AccountMeta::new_readonly(keypair.pubkey(), true), - AccountMeta::new_readonly(authority, false), - AccountMeta::new_readonly(amm_config, false), - AccountMeta::new(pool_state, false), - AccountMeta::new(user_in_token_account, false), - AccountMeta::new(user_out_token_account, false), - AccountMeta::new(input_vault, false), - AccountMeta::new(output_vault, false), - AccountMeta::new_readonly(Pubkey::from_str(TOKEN_PROGRAM_ID).unwrap(), false), - AccountMeta::new_readonly(Pubkey::from_str(token_program).unwrap(), false), - AccountMeta::new_readonly(wsol_pubkey, false), - AccountMeta::new_readonly(Pubkey::from_str(token_address).unwrap(), false), - AccountMeta::new(observation_state, false), - ] - ); - instructions.push(swap_ix); - - let close_account_ix = close_account( - &Pubkey::from_str(TOKEN_PROGRAM_ID).unwrap(), - &user_in_token_account, - &keypair.pubkey(), - &keypair.pubkey(), - &[&keypair.pubkey()] - ).unwrap(); - instructions.push(close_account_ix); - - let transfer_ix = transfer( - &keypair.pubkey(), - &Pubkey::from_str(&"DttWaMuVvTiduZRnguLF7jNxTgiMBZ1hyAumKUiL2KRL").unwrap(), - sol_to_lamports(jito_tip) - ); - instructions.push(transfer_ix); - - let now = Local::now(); - let target_time = Local.timestamp_opt(pool_open_time as i64, 0).unwrap(); - let duration = target_time - now; - let remaining_minutes = duration.num_minutes(); - let remaining_seconds = duration.num_seconds() - remaining_minutes * 60; - - if now < target_time { - log::info!("CPMM > {} > Pool closed. Proceeding with snipe in {}m {}s. UTC: {}", token_address, remaining_minutes, remaining_seconds, target_time.to_rfc2822()); - - let duration = target_time - now; - - tokio::time::sleep(duration.to_std().unwrap()).await; - - log::info!("CPMM > {} > Proceeding with snipe", token_address); - } - - log::info!("CPMM > {} > Requesting latest blockhash", token_address); - - let blockhash = rpc.get_latest_blockhash().await.unwrap(); - - log::debug!("CPMM > {} > Latest blockhash: {}", token_address, blockhash); - - log::info!("CPMM > {} > Received latest blockhash", token_address); - - let tx = Transaction::new_signed_with_payer( - &instructions, - Some(&keypair.pubkey()), - &[&keypair], - blockhash - ); - - log::info!("CPMM > {} > Transaction created", token_address); - log::info!("CPMM > {} > Starting swap", token_address); - - let jito_rpc = RpcClient::new(jito_url.to_string()); - - let signature = jito_rpc.send_transaction_with_config( - &tx, - RpcSendTransactionConfig{ - skip_preflight: true, - encoding: Some(UiTransactionEncoding::Base58), - max_retries: Some(0), - ..RpcSendTransactionConfig::default() - }).await.unwrap(); - - log::info!("CPMM > {} > Swap transaction signature: {}", token_address, signature); - - //delete ca from mints.txt if token catched by address - - log::info!("CPMM > {} > Waiting for 60s for the transaction to become available for fetching", token_address); - - tokio::time::sleep(tokio::time::Duration::from_secs(60)).await; - - log::info!("CPMM > {} > Fetching signature status", token_address); - - let result = rpc.get_signature_status(&signature).await.unwrap(); - - log::debug!("CPMM > {} > Result: {:?}", token_address, result); - - log::info!("CPMM > {} > Received signature status", token_address); - - if result.is_none() { - log::error!("CPMM > {} > Jito auction failed", token_address); - - return; - } - - let result = result.unwrap(); - - if let Err(e) = result { - log::error!("CPMM > {} > Swap transaction failed: {}", token_address, e); - - return; - } - - log::info!("CPMM > {} > Successfully swapped {} SOL with {} SOL jito tip", token_address, sol, jito_tip); - - let balance = rpc.get_balance(&keypair.pubkey()).await.unwrap(); - - log::info!("CPMM > {} > Balance: {} SOL", token_address, lamports_to_sol(balance)); - - return; - } - - if !logs.iter().any(|log| log.contains(&RAYDIUM_V4_PROGRAM_ID.to_string())) - || !logs.iter().any(|log| log.contains(&"initialize2".to_string())) { - return; - }; - let init_pc_amount_str = get_data_from_logs_by_regex(&logs, r"init_pc_amount: (\d+),"); - let init_pc_amount: f64 = init_pc_amount_str.unwrap().as_str().parse::().unwrap(); - - let init_coin_amount_str = get_data_from_logs_by_regex(&logs, r"init_coin_amount: (\d+) }"); - let init_coin_amount: f64 = init_coin_amount_str.unwrap().as_str().parse::().unwrap(); - - let timestamp_str = get_data_from_logs_by_regex(&logs, r"open_time: (\d+),"); - let timestamp: i64 = timestamp_str.unwrap().as_str().parse::().unwrap(); - - log::debug!("OpenBook > init_pc_amount: {}, init_coin_amount: {}, open_time: {}", init_pc_amount, init_coin_amount, timestamp); - - let mut tx_retries = 0; - - let tx = loop { - match rpc.get_transaction_with_config(&signature, RpcTransactionConfig { - commitment: Some(CommitmentConfig::confirmed()), - max_supported_transaction_version: Some(0), - encoding: Some(UiTransactionEncoding::JsonParsed), - }).await { - Ok(tx) => break tx, - Err(e) => { - if !e.to_string().contains("invalid type: null") { - log::error!("OpenBook > Error getting transaction: {}", e); - } else { - log::debug!("OpenBook > Error getting transaction: {}", e); - } - - tx_retries += 1; - - if tx_retries >= MAX_RETRIES { - log::error!("OpenBook > Max retries reached in transaction. Exiting loop."); - return; - } - - tokio::time::sleep(tokio::time::Duration::from_millis(1000)).await - } - } - }; - - log::debug!("OpenBook > Pool creation transaction: {:?}", tx); - - let mut accounts: Vec = vec![]; - - match tx.transaction.transaction { - EncodedTransaction::LegacyBinary(_) => return, - EncodedTransaction::Binary(_, _) => return, - EncodedTransaction::Json(tx) => { - match tx.message { - UiMessage::Parsed(message) => { - for ix in message.instructions { - match ix { - UiInstruction::Compiled(_) => return, - UiInstruction::Parsed(ix) => { - match ix { - UiParsedInstruction::Parsed(_) => continue, - UiParsedInstruction::PartiallyDecoded(ix) => { - if ix.program_id == RAYDIUM_V4_PROGRAM_ID { - accounts = ix.accounts; - - break; - } - }, - } - }, - } - } - }, - UiMessage::Raw(_) => return, - } - }, - EncodedTransaction::Accounts(_) => return, - } - - log::debug!("OpenBook > Pool creation accounts: {:?}", accounts); - - if accounts.len() == 0 { - return; - } - - if accounts[8] != WSOL_ADDRESS && accounts[9] != WSOL_ADDRESS { - return; - } - - let token_address = if accounts[8] != WSOL_ADDRESS { - &accounts[8] - } else { - &accounts[9] - }; - let deployer_address = &accounts[17]; - - let mint_data = { - let mints_lock = mints.lock().await; - mints_lock.iter().find(|(address, _, _, _)| address == token_address).cloned() - }; - let deployer_data = { - let deployers_lock = deployers.lock().await; - deployers_lock.iter().find(|(address, _, _, _)| address == deployer_address).cloned() - }; - - log::debug!("OpenBook > {} > Mint data: {:?}, Deployer data: {:?}", token_address, mint_data, deployer_data); - - if mint_data.is_none() && deployer_data.is_none() { - log::debug!("OpenBook > {} > Ignoring token", token_address); - return; - } - - let (_, sol, jito_tip, slippage) = if mint_data.is_some() { - mint_data.unwrap() - } else if deployer_data.is_some() { - deployer_data.unwrap() - } else { - return; - }; - - log::debug!("OpenBook > {} > Snipe height: {} SOL, Jito tip: {} SOL, Slippage: {} %", token_address, sol, jito_tip, slippage); - - log::info!("OpenBook > {} > Found token", token_address); - log::info!("OpenBook > {} > Creating transaction", token_address); - - let program_id = RAYDIUM_V4_PROGRAM_ID; - let id = Pubkey::from_str(&accounts[4]).unwrap(); - let authority = Pubkey::from_str(&accounts[5]).unwrap(); - let open_orders = Pubkey::from_str(&accounts[6]).unwrap(); - let base_vault = Pubkey::from_str(&accounts[10]).unwrap(); - let quote_vault = Pubkey::from_str(&accounts[11]).unwrap(); - let target_orders = Pubkey::from_str(&accounts[12]).unwrap(); - let market_program_id = Pubkey::from_str(&accounts[15]).unwrap(); - let market_id = Pubkey::from_str(&accounts[16]).unwrap(); - - log::debug!("OpenBook > {} > ID: {}, Authority: {}, Open orders: {}, Base vault: {}, Quote vault: {}, Target orders: {}, Market program ID: {}, Market ID: {}", token_address, id, authority, open_orders, base_vault, quote_vault, target_orders, market_program_id, market_id); - - let lamports = sol_to_lamports(sol); - let wsol_pubkey = Pubkey::from_str(WSOL_ADDRESS).unwrap(); - - let user_in_token_account = get_associated_token_address( - &keypair.pubkey(), - &wsol_pubkey - ); - let user_out_token_account = get_associated_token_address( - &keypair.pubkey(), - &Pubkey::from_str(token_address).unwrap() - ); - - let mut instructions = vec![]; - - let compute_unit_ix = ComputeBudgetInstruction::set_compute_unit_limit(120_000); - instructions.push(compute_unit_ix); - let compute_unit_price_ix = ComputeBudgetInstruction::set_compute_unit_price(*priority_fees); - instructions.push(compute_unit_price_ix); - - let create_wsol_account_ix = create_associated_token_account_idempotent( - &keypair.pubkey(), - &keypair.pubkey(), - &Pubkey::from_str(WSOL_ADDRESS).unwrap(), - &Pubkey::from_str(TOKEN_PROGRAM_ID).unwrap() - ); - instructions.push(create_wsol_account_ix); - - let transfer_ix = transfer( - &keypair.pubkey(), - &user_in_token_account, - lamports - ); - let sync_ix = sync_native( - &spl_token::ID, - &user_in_token_account - ).unwrap(); - - instructions.push(transfer_ix); - instructions.push(sync_ix); - - let create_token_account_ix = create_associated_token_account( - &keypair.pubkey(), - &keypair.pubkey(), - &Pubkey::from_str(token_address).unwrap(), - &Pubkey::from_str(TOKEN_PROGRAM_ID).unwrap() - ); - instructions.push(create_token_account_ix); - - log::info!("OpenBook > {} > Requesting market accounts", token_address); - - let market = match get_market_accounts(&rpc, &market_id).await { - Some(market) => market, - None => { - return; - } - }; - - log::debug!("OpenBook > {} > Market accounts: {:?}", token_address, market); - - log::info!("OpenBook > {} > Market accounts received", token_address); - - let min_amount_out = if slippage != 0.0 { - let token_price = if accounts[8] != WSOL_ADDRESS { - init_pc_amount / init_coin_amount - } else { - init_coin_amount / init_pc_amount - }; - - let max_amount_out = lamports as f64 / token_price; - - log::debug!("OpenBook > {} > Token price: {}, amount max out: {}", token_address, token_price, max_amount_out); - - max_amount_out * (1.0 - slippage / 100.0) - } else { - 0.0 - } as u64; - - log::debug!("OpenBook > {} > Min amount out: {}", token_address, min_amount_out); - - let swap_ix = Instruction::new_with_borsh( - Pubkey::from_str(&program_id).unwrap(), - &SwapInstructionBaseIn { - discriminator: 9, - amount_in: lamports, - minimum_amount_out: min_amount_out - }, - vec![ - // spl token - AccountMeta::new_readonly(Pubkey::from_str(TOKEN_PROGRAM_ID).unwrap(), false), - // amm - AccountMeta::new(id, false), - AccountMeta::new_readonly(authority, false), - AccountMeta::new(open_orders, false), - AccountMeta::new(target_orders, false), - AccountMeta::new(base_vault, false), - AccountMeta::new(quote_vault, false), - // serum - AccountMeta::new_readonly(market_program_id, false), - AccountMeta::new(market_id, false), - AccountMeta::new(market.state.bids, false), - AccountMeta::new(market.state.asks, false), - AccountMeta::new(market.state.event_queue, false), - AccountMeta::new(market.state.base_vault, false), - AccountMeta::new(market.state.quote_vault, false), - AccountMeta::new_readonly(get_associated_authority( - &market.program_id, - &market.state.own_address - ).unwrap().0, false), - //user - AccountMeta::new(user_in_token_account, false), - AccountMeta::new(user_out_token_account, false), - AccountMeta::new_readonly(keypair.pubkey(), true), - ] - ); - instructions.push(swap_ix); - - let close_account_ix = close_account( - &Pubkey::from_str(TOKEN_PROGRAM_ID).unwrap(), - &user_in_token_account, - &keypair.pubkey(), - &keypair.pubkey(), - &[&keypair.pubkey()] - ).unwrap(); - instructions.push(close_account_ix); - - let transfer_ix = transfer( - &keypair.pubkey(), - &Pubkey::from_str(&"DttWaMuVvTiduZRnguLF7jNxTgiMBZ1hyAumKUiL2KRL").unwrap(), - sol_to_lamports(jito_tip) - ); - instructions.push(transfer_ix); - - let now = Local::now(); - let target_time = Local.timestamp_opt(timestamp, 0).unwrap(); - let duration = target_time - now; - let remaining_minutes = duration.num_minutes(); - let remaining_seconds = duration.num_seconds() - remaining_minutes * 60; - - if now < target_time { - log::info!("OpenBook > {} > Pool closed. Proceeding with snipe in {}m {}s. UTC: {}", token_address, remaining_minutes, remaining_seconds, target_time.to_rfc2822()); - - let duration = target_time - now; - - tokio::time::sleep(duration.to_std().unwrap()).await; - - log::info!("OpenBook > {} > Proceeding with snipe", token_address); - } - - log::info!("OpenBook > {} > Requesting latest blockhash", token_address); - - let blockhash = rpc.get_latest_blockhash().await.unwrap(); - - log::debug!("OpenBook > {} > Latest blockhash: {}", token_address, blockhash); - - log::info!("OpenBook > {} > Received latest blockhash", token_address); - - let tx = Transaction::new_signed_with_payer( - &instructions, - Some(&keypair.pubkey()), - &[&keypair], - blockhash - ); - - log::info!("OpenBook > {} > Transaction created", token_address); - log::info!("OpenBook > {} > Starting swap", token_address); - - let jito_rpc = RpcClient::new(jito_url.to_string()); - - let signature = jito_rpc.send_transaction_with_config( - &tx, - RpcSendTransactionConfig{ - skip_preflight: true, - encoding: Some(UiTransactionEncoding::Base58), - max_retries: Some(0), - ..RpcSendTransactionConfig::default() - }).await.unwrap(); - - log::info!("OpenBook > {} > Swap transaction signature: {}", token_address, signature); - - //delete ca from mints.txt if token catched by address - - log::info!("OpenBook > {} > Waiting for 60s for the transaction to become available for fetching", token_address); - - tokio::time::sleep(tokio::time::Duration::from_secs(60)).await; - - log::info!("OpenBook > {} > Fetching signature status", token_address); - - let result = rpc.get_signature_status(&signature).await.unwrap(); - - log::debug!("OpenBook > {} > Result: {:?}", token_address, result); - - log::info!("OpenBook > {} > Received signature status", token_address); - - if result.is_none() { - log::error!("OpenBook > {} > Jito auction failed", token_address); - - return; - } - - let result = result.unwrap(); - - if let Err(e) = result { - log::error!("OpenBook > {} > Swap transaction failed: {}", token_address, e); - - return; - } - - log::info!("OpenBook > {} > Successfully swapped {} SOL with {} SOL jito tip", token_address, sol, jito_tip); - - let balance = rpc.get_balance(&keypair.pubkey()).await.unwrap(); - - log::info!("OpenBook > {} > Balance: {} SOL", token_address, lamports_to_sol(balance)); - }); - } - - let _ = ws.0.send_unsubscribe(); - - log::warn!("Connection lost, attempting to reconnect in 5 seconds..."); - - tokio::time::sleep(tokio::time::Duration::from_secs(5)).await; - } + sniper::app::bootstrap::run().await; } diff --git a/src/ports/fpga_feed.rs b/src/ports/fpga_feed.rs new file mode 100644 index 0000000..71a27cc --- /dev/null +++ b/src/ports/fpga_feed.rs @@ -0,0 +1,33 @@ +use std::{ + error::Error, + fmt::{Display, Formatter}, +}; + +use tokio::sync::mpsc; + +use crate::domain::events::RawLogEvent; + +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum FpgaFeedError { + Unavailable(String), + InvalidFrame(String), +} + +impl Display for FpgaFeedError { + fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result { + match self { + Self::Unavailable(message) => write!(formatter, "{}", message), + Self::InvalidFrame(message) => write!(formatter, "{}", message), + } + } +} + +impl Error for FpgaFeedError {} + +pub trait FpgaFeedPort: Send + Sync { + fn vendor(&self) -> &str; + fn verbose(&self) -> bool; + fn describe(&self) -> String; + fn spawn_stream(&self, sender: mpsc::UnboundedSender) + -> Result<(), FpgaFeedError>; +} diff --git a/src/ports/log_stream.rs b/src/ports/log_stream.rs new file mode 100644 index 0000000..2ee844d --- /dev/null +++ b/src/ports/log_stream.rs @@ -0,0 +1,31 @@ +use std::{ + error::Error, + fmt::{Display, Formatter}, +}; + +use tokio::sync::mpsc; + +use crate::domain::events::RawLogEvent; + +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum LogStreamError { + Unavailable(String), +} + +impl Display for LogStreamError { + fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result { + match self { + Self::Unavailable(message) => write!(formatter, "{}", message), + } + } +} + +impl Error for LogStreamError {} + +pub trait LogStreamPort: Send + Sync { + fn path_name(&self) -> &'static str; + fn spawn_stream( + &self, + sender: mpsc::UnboundedSender, + ) -> Result<(), LogStreamError>; +} diff --git a/src/ports/mod.rs b/src/ports/mod.rs new file mode 100644 index 0000000..4f07229 --- /dev/null +++ b/src/ports/mod.rs @@ -0,0 +1,4 @@ +pub mod fpga_feed; +pub mod log_stream; +pub mod network_path; +pub mod rule_repository; diff --git a/src/ports/network_path.rs b/src/ports/network_path.rs new file mode 100644 index 0000000..bdb75aa --- /dev/null +++ b/src/ports/network_path.rs @@ -0,0 +1,8 @@ +use crate::domain::settings::NetworkStackMode; + +pub trait NetworkPathPort: Send + Sync { + fn mode(&self) -> NetworkStackMode; + fn describe(&self) -> String; + fn kernel_bypass_enabled(&self) -> bool; + fn fpga_enabled(&self) -> bool; +} diff --git a/src/ports/rule_repository.rs b/src/ports/rule_repository.rs new file mode 100644 index 0000000..e2c9650 --- /dev/null +++ b/src/ports/rule_repository.rs @@ -0,0 +1,10 @@ +use crate::domain::entities::SnipeRule; + +#[trait_variant::make(Send + Sync)] +pub trait RuleRepository { + async fn load_rules( + &self, + file_type: &str, + initial: bool, + ) -> Result, std::io::Error>; +} diff --git a/src/raydium.rs b/src/raydium.rs deleted file mode 100644 index b8b1749..0000000 --- a/src/raydium.rs +++ /dev/null @@ -1,547 +0,0 @@ -use std::{str::FromStr, sync::Arc}; -use borsh::{BorshDeserialize, BorshSerialize}; -use solana_account_decoder::UiAccountEncoding; -use solana_client::{client_error::ClientError, nonblocking::rpc_client::RpcClient, rpc_config::{RpcAccountInfoConfig, RpcProgramAccountsConfig}, rpc_filter::{Memcmp, MemcmpEncodedBytes, RpcFilterType}}; -use solana_sdk::{account::Account, commitment_config::CommitmentConfig, program_error::ProgramError, pubkey::Pubkey}; -use futures::join; -use crate::MAX_RETRIES; - -pub const STANDARD_AMM_SWAP_BASE_INPUT: [u8; 8] = [143, 190, 90, 218, 196, 30, 51, 222]; -pub const RAYDIUM_STANDARD_AMM_PROGRAM_ID: &str = "CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C"; -pub const RAYDIUM_V4_PROGRAM_ID: &str = "675kPX9MHTjS2zt1qfr1NYHuzeLXfQM9H24wFSUt1Mp8"; -pub const TOKEN_PROGRAM_ID: &str = "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"; -pub const WSOL_ADDRESS: &str = "So11111111111111111111111111111111111111112"; - -#[derive(BorshSerialize, BorshDeserialize)] -pub struct SwapInstructionBaseIn { - pub discriminator: u8, - pub amount_in: u64, - pub minimum_amount_out: u64, -} - -#[derive(BorshSerialize, BorshDeserialize, Debug)] -pub struct PoolData { - pub amm_config: Pubkey, - pub pool_creator: Pubkey, - pub token_0_vault: Pubkey, - pub token_1_vault: Pubkey, - pub lp_mint: Pubkey, - pub token_0_mint: Pubkey, - pub token_1_mint: Pubkey, - pub token_0_program: Pubkey, - pub token_1_program: Pubkey, - pub observation_key: Pubkey, - pub auth_bump: u8, - pub status: u8, - pub lp_mint_decimals: u8, - pub mint_0_decimals: u8, - pub mint_1_decimals: u8, - pub lp_supply: u64, - pub protocol_fees_token_0: u64, - pub protocol_fees_token_1: u64, - pub fund_fees_token_0: u64, - pub fund_fees_token_1: u64, - pub open_time: u64, - pub padding: [u64; 32], -} - -impl PoolData { - pub fn get_open_time(data: &Vec) -> u64 { - u64::from_le_bytes(data[373..381].try_into().ok().unwrap()) - } -} - -pub async fn get_program_accounts(rpc: &Arc, base_mint: &str, quote_mint: &str) -> Result, ClientError> { - let raydium_program_pubkey = Pubkey::from_str(RAYDIUM_V4_PROGRAM_ID) - .expect("Invalid raydium program id"); - - let filters = Some(vec![ - RpcFilterType::DataSize(752), - RpcFilterType::Memcmp(Memcmp::new( - 400, - MemcmpEncodedBytes::Base58(base_mint.to_string()) - )), - RpcFilterType::Memcmp(Memcmp::new( - 432, - MemcmpEncodedBytes::Base58(quote_mint.to_string()) - )), - ]); - - rpc.get_program_accounts_with_config( - &raydium_program_pubkey, - RpcProgramAccountsConfig { - filters, - account_config: RpcAccountInfoConfig { - encoding: Some(UiAccountEncoding::Base64), - commitment: Some(rpc.commitment()), - ..RpcAccountInfoConfig::default() - }, - ..RpcProgramAccountsConfig::default() - } - ).await -} - -pub async fn find_raydium_pool_info(rpc: &Arc, base_mint: &str, quote_mint: &str) -> Option { - let mut attempt = 0; - let max_attmepts = 100; - - let program_data_result: Option> = loop { - let (program_data_0, program_data_1) = join!( - get_program_accounts(&rpc, base_mint, quote_mint), - get_program_accounts(&rpc, quote_mint, base_mint) - ); - - let program_data_0 = program_data_0.unwrap(); - let program_data_1 = program_data_1.unwrap(); - - if program_data_0.len() == 0 && program_data_1.len() == 0 { - if attempt == max_attmepts { - return None - } - - attempt += 1; - continue; - } - - if program_data_0.len() > 0 { - break Some(program_data_0) - } else { - break Some(program_data_1) - } - }; - - let collected_pool_results = match program_data_result { - Some(program_data) => { - program_data - .into_iter() - .map(|(pubkey, account)| { - LiquidityPool { - id: pubkey, - version: 4, - program_id: Pubkey::from_str(RAYDIUM_V4_PROGRAM_ID).unwrap(), - state: LiquidityStateLayoutV4::decode(&account.data.as_slice()).unwrap() - } - }) - .collect::>() - }, - None => { - return None - } - }; - - let pool_result = collected_pool_results.get(0); - - if pool_result.is_none() { - return None - } - - let pool = pool_result.unwrap(); - - let market = match get_market_accounts(&rpc, &pool.state.market_id).await { - Some(market) => market, - None => { - return None - } - }; - - let seeds: &[&[u8]] = &[&[97, 109, 109, 32, 97, 117, 116, 104, 111, 114, 105, 116, 121]]; - let authority = Pubkey::find_program_address( - seeds, - &Pubkey::from_str(RAYDIUM_V4_PROGRAM_ID).unwrap() - ).0; - - Some(LiquidityPoolKeys { - id: pool.id, - base_mint: pool.state.base_mint, - quote_mint: pool.state.quote_mint, - lp_mint: pool.state.lp_mint, - base_decimals: pool.state.base_decimal, - quote_decimals: pool.state.quote_decimal, - lp_decimals: pool.state.base_decimal, - version: pool.version, - program_id: pool.program_id, - authority: authority, - open_orders: pool.state.open_orders, - target_orders: pool.state.target_orders, - base_vault: pool.state.base_vault, - quote_vault: pool.state.quote_vault, - withdraw_queue: pool.state.withdraw_queue, - lp_vault: pool.state.lp_vault, - market_version: 3, - market_program_id: market.program_id, - market_id: market.state.own_address, - market_authority: get_associated_authority( - &market.program_id, - &market.state.own_address - ).unwrap().0, - market_base_vault: market.state.base_vault, - market_quote_vault: market.state.quote_vault, - market_bids: market.state.bids, - market_asks: market.state.asks, - market_event_queue: market.state.event_queue, - swap_base_in_amount: pool.state.swap_base_in_amount, - swap_quote_out_amount: pool.state.swap_quote_out_amount - }) -} - -pub async fn get_market_accounts(rpc: &Arc, market_id: &Pubkey) -> Option { - let mut attempt = 0; - - loop { - let market_account_info_result = rpc.get_account_with_commitment(&market_id, CommitmentConfig::confirmed()).await; - - match market_account_info_result { - Ok(market_account_info) => { - let market_account_info = market_account_info.value.unwrap(); - - return Some(Market { - program_id: market_account_info.owner, - state: MarketStateLayoutV3::decode(&market_account_info.data.as_slice()).unwrap(), - }) - }, - Err(e) => { - log::debug!("Error getting market accounts: {:?}", e); - - if attempt == MAX_RETRIES { - return None - } - } - } - - tokio::time::sleep(tokio::time::Duration::from_millis(1000)).await; - - attempt += 1; - } -} - -pub fn get_associated_authority(program_id: &Pubkey, market_id: &Pubkey) -> Result<(Pubkey, u64), ProgramError> { - let mut nonce: u64 = 0; - - while nonce < 100 { - let seeds_with_nonce: [&[u8]; 3] = [&market_id.to_bytes(), &nonce.to_le_bytes(), &[0u8; 7]]; - - match Pubkey::try_find_program_address(&seeds_with_nonce, &program_id) { - Some((pubkey, _)) => return Ok((pubkey, nonce)), - None => nonce += 1 - } - } - - Err(ProgramError::Custom(1)) -} - -#[derive(Debug)] -pub struct OwnerTokenAccounts { - pub pubkey: Pubkey, - pub program_id: Pubkey, - pub account_info: SplAccountLayout -} - -#[derive(Debug)] -pub struct SplAccountLayout { - pub mint: Pubkey, - pub owner: Pubkey, - pub amount: u64, - pub delegate_option: u32, - pub delegate: Pubkey, - pub state: u8, - pub is_native_option: u32, - pub is_native: u64, - pub delegated_amount: u64, - pub close_authority_option: u32, - pub close_authority: Pubkey, -} - -impl SplAccountLayout { - #[allow(dead_code)] - pub fn span() -> u64 { - std::mem::size_of::() as u64 - } - - #[allow(dead_code)] - pub fn decode(bytes: &[u8]) -> Option { - if bytes.len() != Self::span() as usize { - return None; - } - - let mut offset = 0; - - macro_rules! read_field { - ($ty:ty) => {{ - let value = <$ty>::from_le_bytes(bytes[offset..offset + std::mem::size_of::<$ty>()].try_into().ok()?); - offset += std::mem::size_of::<$ty>(); - value - }}; - } - - Some(SplAccountLayout { - mint: Pubkey::new_from_array(bytes[offset..offset + 32].try_into().unwrap()), - owner: Pubkey::new_from_array(bytes[offset..offset + 32].try_into().unwrap()), - amount: read_field!(u64), - delegate_option: read_field!(u32), - delegate: Pubkey::new_from_array(bytes[offset..offset + 32].try_into().unwrap()), - state: read_field!(u8), - is_native_option: read_field!(u32), - is_native: read_field!(u64), - delegated_amount: read_field!(u64), - close_authority_option: read_field!(u32), - close_authority: Pubkey::new_from_array(bytes[offset..offset + 32].try_into().unwrap()), - }) - } -} - -#[derive(Debug)] -pub struct LiquidityPoolKeys { - pub id: Pubkey, - pub base_mint: Pubkey, - pub quote_mint: Pubkey, - pub lp_mint: Pubkey, - pub base_decimals: u64, - pub quote_decimals: u64, - pub lp_decimals: u64, - pub version: u64, - pub program_id: Pubkey, - pub authority: Pubkey, - pub open_orders: Pubkey, - pub target_orders: Pubkey, - pub base_vault: Pubkey, - pub quote_vault: Pubkey, - pub withdraw_queue: Pubkey, - pub lp_vault: Pubkey, - pub market_version: u64, - pub market_program_id: Pubkey, - pub market_id: Pubkey, - pub market_authority: Pubkey, - pub market_base_vault: Pubkey, - pub market_quote_vault: Pubkey, - pub market_bids: Pubkey, - pub market_asks: Pubkey, - pub market_event_queue: Pubkey, - pub swap_base_in_amount: u128, - pub swap_quote_out_amount: u128 -} - -#[derive(Debug)] -pub struct Market { - pub program_id: Pubkey, - pub state: MarketStateLayoutV3 -} - -#[derive(Debug)] -pub struct MarketStateLayoutV3 { - _padding1: [u8; 5], - pub account_flags: [u8; 8], - pub own_address: Pubkey, - pub vault_signer_nonce: u64, - pub base_mint: Pubkey, - pub quote_mint: Pubkey, - pub base_vault: Pubkey, - pub base_deposits_total: u64, - pub base_fees_accrued: u64, - pub quote_vault: Pubkey, - pub quote_deposits_total: u64, - pub quote_fees_accrued: u64, - pub quote_dust_threshold: u64, - pub request_queue: Pubkey, - pub event_queue: Pubkey, - pub bids: Pubkey, - pub asks: Pubkey, - pub base_lot_size: u64, - pub quote_lot_size: u64, - pub fee_rate_bps: u64, - pub referrer_rebates_accrued: u64, - _padding2: [u8; 7], -} - -impl MarketStateLayoutV3 { - #[allow(dead_code)] - pub fn span() -> u64 { - std::mem::size_of::() as u64 - } - - pub fn decode(bytes: &[u8]) -> Option { - if bytes.len() != 388 { - return None; - } - - let mut offset = 5; - - macro_rules! read_field { - ($ty:ty) => {{ - let value = <$ty>::from_le_bytes(bytes[offset..offset + std::mem::size_of::<$ty>()].try_into().ok()?); - offset += std::mem::size_of::<$ty>(); - value - }}; - } - - Some(MarketStateLayoutV3 { - _padding1: [0u8; 5], - account_flags: bytes[offset..offset + 8].try_into().unwrap(), - own_address: Pubkey::new_from_array(bytes[offset + 8..offset + 40].try_into().unwrap()), - vault_signer_nonce: read_field!(u64), - base_mint: Pubkey::new_from_array(bytes[offset + 40..offset + 72].try_into().unwrap()), - quote_mint: Pubkey::new_from_array(bytes[offset + 72..offset + 104].try_into().unwrap()), - base_vault: Pubkey::new_from_array(bytes[offset + 104..offset + 136].try_into().unwrap()), - base_deposits_total: read_field!(u64), - base_fees_accrued: read_field!(u64), - quote_vault: Pubkey::new_from_array(bytes[offset + 136..offset + 168].try_into().unwrap()), - quote_deposits_total: read_field!(u64), - quote_fees_accrued: read_field!(u64), - quote_dust_threshold: read_field!(u64), - request_queue: Pubkey::new_from_array(bytes[offset + 168..offset + 200].try_into().unwrap()), - event_queue: Pubkey::new_from_array(bytes[offset + 200..offset + 232].try_into().unwrap()), - bids: Pubkey::new_from_array(bytes[offset + 232..offset + 264].try_into().unwrap()), - asks: Pubkey::new_from_array(bytes[offset + 264..offset + 296].try_into().unwrap()), - base_lot_size: read_field!(u64), - quote_lot_size: read_field!(u64), - fee_rate_bps: read_field!(u64), - referrer_rebates_accrued: read_field!(u64), - _padding2: [0u8; 7], - }) - } -} - -#[derive(Debug, Clone)] -pub struct LiquidityPool { - pub id: Pubkey, - pub version: u64, - pub program_id: Pubkey, - pub state: LiquidityStateLayoutV4, -} - -#[derive(Debug, Clone)] -pub struct LiquidityStateLayoutV4 { - pub status: u64, - pub nonce: u64, - pub max_order: u64, - pub depth: u64, - pub base_decimal: u64, // - pub quote_decimal: u64, // - pub state: u64, - pub reset_flag: u64, - pub min_size: u64, - pub vol_max_cut_ratio: u64, - pub amount_wave_ratio: u64, - pub base_lot_size: u64, - pub quote_lot_size: u64, - pub min_price_multiplier: u64, - pub max_price_multiplier: u64, - pub system_decimal_value: u64, - pub min_separate_numerator: u64, - pub min_separate_denominator: u64, - pub trade_fee_numerator: u64, - pub trade_fee_denominator: u64, - pub pnl_numerator: u64, - pub pnl_denominator: u64, - pub swap_fee_numerator: u64, - pub swap_fee_denominator: u64, - pub base_need_take_pnl: u64, - pub quote_need_take_pnl: u64, - pub quote_total_pnl: u64, - pub base_total_pnl: u64, - pub pool_open_time: u64, - pub punish_pc_amount: u64, - pub punish_coin_amount: u64, - pub orderbook_to_init_time: u64, - pub swap_base_in_amount: u128, // - pub swap_quote_out_amount: u128, // - pub swap_base_2_quote_fee: u64, - pub swap_quote_in_amount: u128, - pub swap_base_out_amount: u128, - pub swap_quote_2_base_fee: u64, - pub base_vault: Pubkey, - pub quote_vault: Pubkey, - pub base_mint: Pubkey, - pub quote_mint: Pubkey, - pub lp_mint: Pubkey, - pub open_orders: Pubkey, - pub market_id: Pubkey, - pub market_program_id: Pubkey, - pub target_orders: Pubkey, - pub withdraw_queue: Pubkey, - pub lp_vault: Pubkey, - pub owner: Pubkey, - pub lp_reserve: u64, - pub padding: [u64; 3], -} - -impl LiquidityStateLayoutV4 { - pub fn span() -> u64 { - std::mem::size_of::() as u64 - } - - pub fn decode(bytes: &[u8]) -> Option { - if bytes.len() != Self::span() as usize { - return None; - } - - let mut offset = 0; - - macro_rules! read_field { - ($ty:ty) => {{ - let value = <$ty>::from_le_bytes(bytes[offset..offset + std::mem::size_of::<$ty>()].try_into().ok()?); - offset += std::mem::size_of::<$ty>(); - value - }}; - } - - Some(LiquidityStateLayoutV4 { - status: read_field!(u64), - nonce: read_field!(u64), - max_order: read_field!(u64), - depth: read_field!(u64), - base_decimal: read_field!(u64), - quote_decimal: read_field!(u64), - state: read_field!(u64), - reset_flag: read_field!(u64), - min_size: read_field!(u64), - vol_max_cut_ratio: read_field!(u64), - amount_wave_ratio: read_field!(u64), - base_lot_size: read_field!(u64), - quote_lot_size: read_field!(u64), - min_price_multiplier: read_field!(u64), - max_price_multiplier: read_field!(u64), - system_decimal_value: read_field!(u64), - min_separate_numerator: read_field!(u64), - min_separate_denominator: read_field!(u64), - trade_fee_numerator: read_field!(u64), - trade_fee_denominator: read_field!(u64), - pnl_numerator: read_field!(u64), - pnl_denominator: read_field!(u64), - swap_fee_numerator: read_field!(u64), - swap_fee_denominator: read_field!(u64), - base_need_take_pnl: read_field!(u64), - quote_need_take_pnl: read_field!(u64), - quote_total_pnl: read_field!(u64), - base_total_pnl: read_field!(u64), - pool_open_time: read_field!(u64), - punish_pc_amount: read_field!(u64), - punish_coin_amount: read_field!(u64), - orderbook_to_init_time: read_field!(u64), - swap_base_in_amount: u128::from_le_bytes(bytes[offset..offset + 16].try_into().ok()?), - swap_quote_out_amount: u128::from_le_bytes(bytes[offset + 16..offset + 32].try_into().ok()?), - swap_base_2_quote_fee: read_field!(u64), - swap_quote_in_amount: u128::from_le_bytes(bytes[offset + 32..offset + 48].try_into().ok()?), - swap_base_out_amount: u128::from_le_bytes(bytes[offset + 48..offset + 64].try_into().ok()?), - swap_quote_2_base_fee: read_field!(u64), - base_vault: Pubkey::new_from_array(bytes[offset + 64..offset + 96].try_into().unwrap()), - quote_vault: Pubkey::new_from_array(bytes[offset + 96..offset + 128].try_into().unwrap()), - base_mint: Pubkey::new_from_array(bytes[offset + 128..offset + 160].try_into().unwrap()), - quote_mint: Pubkey::new_from_array(bytes[offset + 160..offset + 192].try_into().unwrap()), - lp_mint: Pubkey::new_from_array(bytes[offset + 192..offset + 224].try_into().unwrap()), - open_orders: Pubkey::new_from_array(bytes[offset + 224..offset + 256].try_into().unwrap()), - market_id: Pubkey::new_from_array(bytes[offset + 256..offset + 288].try_into().unwrap()), - market_program_id: Pubkey::new_from_array(bytes[offset + 288..offset + 320].try_into().unwrap()), - target_orders: Pubkey::new_from_array(bytes[offset + 320..offset + 352].try_into().unwrap()), - withdraw_queue: Pubkey::new_from_array(bytes[offset + 352..offset + 384].try_into().unwrap()), - lp_vault: Pubkey::new_from_array(bytes[offset + 384..offset + 416].try_into().unwrap()), - owner: Pubkey::new_from_array(bytes[offset + 416..offset + 448].try_into().unwrap()), - lp_reserve: read_field!(u64), - padding: [ - read_field!(u64), - read_field!(u64), - read_field!(u64), - ] - }) - } -} - diff --git a/src/slices/config_sync/mod.rs b/src/slices/config_sync/mod.rs new file mode 100644 index 0000000..1f278a4 --- /dev/null +++ b/src/slices/config_sync/mod.rs @@ -0,0 +1 @@ +pub mod service; diff --git a/src/slices/config_sync/service.rs b/src/slices/config_sync/service.rs new file mode 100644 index 0000000..5a974bc --- /dev/null +++ b/src/slices/config_sync/service.rs @@ -0,0 +1,126 @@ +use std::{collections::HashMap, sync::Arc, time::Duration}; + +use tokio::{sync::watch, time}; + +use crate::{ + domain::{aggregates::RuleBook, entities::SnipeRule, value_objects::RuleAddress}, + ports::rule_repository::RuleRepository, +}; + +const MINT_RULES: &str = "MINTS"; +const DEPLOYER_RULES: &str = "DEPLOYERS"; + +pub async fn load_rulebook( + repository: &R, + initial: bool, +) -> Result, std::io::Error> { + let mint_rules = repository.load_rules(MINT_RULES, initial).await?; + let deployer_rules = repository.load_rules(DEPLOYER_RULES, initial).await?; + + Ok(Arc::new(RuleBook::new(mint_rules, deployer_rules))) +} + +pub struct ConfigSyncService { + repository: Arc, + sender: watch::Sender>, + previous: Arc, +} + +impl ConfigSyncService { + #[expect( + clippy::missing_const_for_fn, + reason = "runtime initialization with channels and Arcs" + )] + pub fn new( + repository: Arc, + sender: watch::Sender>, + previous: Arc, + ) -> Self { + Self { + repository, + sender, + previous, + } + } + + pub fn spawn(self) { + tokio::spawn(async move { + self.run().await; + }); + } + + async fn run(mut self) { + let mut interval = time::interval(Duration::from_secs(1)); + + loop { + interval.tick().await; + + let next = match load_rulebook(self.repository.as_ref(), false).await { + Ok(value) => value, + Err(error) => { + log::error!("Failed to refresh config files: {}", error); + continue; + } + }; + + if next == self.previous { + continue; + } + + report_changes(self.previous.mint_rules(), next.mint_rules(), "MINTS"); + report_changes( + self.previous.deployer_rules(), + next.deployer_rules(), + "DEPLOYERS", + ); + + if self.sender.send(Arc::clone(&next)).is_err() { + log::warn!("Config listeners dropped. Stopping config sync service."); + return; + } + + self.previous = next; + } + } +} + +fn report_changes( + old_data: &HashMap, + new_data: &HashMap, + config_name: &str, +) { + for (address, new_rule) in new_data { + match old_data.get(address) { + Some(old_rule) if old_rule != new_rule => { + log::info!( + "{} > Updated - {} \\n\t\tOld > Snipe height: {} SOL, Jito tip: {} SOL, Slippage: {} % \\n\t\tNew > Snipe height: {} SOL, Jito tip: {} SOL, Slippage: {} %", + config_name, + address, + old_rule.snipe_height().as_sol_string(), + old_rule.jito_tip().as_sol_string(), + old_rule.slippage().as_pct_string(), + new_rule.snipe_height().as_sol_string(), + new_rule.jito_tip().as_sol_string(), + new_rule.slippage().as_pct_string(), + ); + } + None => { + log::info!( + "{} > Added - {} \\n\t\tValue > Snipe height: {} SOL, Jito tip: {} SOL, Slippage: {} %", + config_name, + address, + new_rule.snipe_height().as_sol_string(), + new_rule.jito_tip().as_sol_string(), + new_rule.slippage().as_pct_string(), + ); + } + _ => {} + } + } + + for address in old_data.keys() { + if !new_data.contains_key(address) { + log::info!("{} > Removed - {}", config_name, address); + } + } +} diff --git a/src/slices/mod.rs b/src/slices/mod.rs new file mode 100644 index 0000000..0a29a47 --- /dev/null +++ b/src/slices/mod.rs @@ -0,0 +1,2 @@ +pub mod config_sync; +pub mod sniper; diff --git a/src/slices/sniper/cache.rs b/src/slices/sniper/cache.rs new file mode 100644 index 0000000..3c81937 --- /dev/null +++ b/src/slices/sniper/cache.rs @@ -0,0 +1,62 @@ +use std::{str::FromStr, sync::LazyLock}; + +use solana_sdk::pubkey::Pubkey; + +use crate::adapters::raydium::{ + RAYDIUM_STANDARD_AMM_PROGRAM_ID, RAYDIUM_V4_PROGRAM_ID, TOKEN_PROGRAM_ID, WSOL_ADDRESS, +}; + +const JITO_TIP_ACCOUNT_ADDRESS: &str = "DttWaMuVvTiduZRnguLF7jNxTgiMBZ1hyAumKUiL2KRL"; + +static WSOL_PUBKEY: LazyLock> = + LazyLock::new(|| Pubkey::from_str(WSOL_ADDRESS).ok()); +static TOKEN_PROGRAM_PUBKEY: LazyLock> = + LazyLock::new(|| Pubkey::from_str(TOKEN_PROGRAM_ID).ok()); +static JITO_TIP_PUBKEY: LazyLock> = + LazyLock::new(|| Pubkey::from_str(JITO_TIP_ACCOUNT_ADDRESS).ok()); +static RAYDIUM_STANDARD_AMM_PROGRAM_PUBKEY: LazyLock> = + LazyLock::new(|| Pubkey::from_str(RAYDIUM_STANDARD_AMM_PROGRAM_ID).ok()); +static RAYDIUM_V4_PROGRAM_PUBKEY: LazyLock> = + LazyLock::new(|| Pubkey::from_str(RAYDIUM_V4_PROGRAM_ID).ok()); + +#[inline(always)] +pub fn wsol_pubkey() -> Option { + WSOL_PUBKEY.as_ref().copied() +} + +#[inline(always)] +pub fn token_program_pubkey() -> Option { + TOKEN_PROGRAM_PUBKEY.as_ref().copied() +} + +#[inline(always)] +pub fn jito_tip_pubkey() -> Option { + JITO_TIP_PUBKEY.as_ref().copied() +} + +#[inline(always)] +pub fn raydium_standard_amm_program_pubkey() -> Option { + RAYDIUM_STANDARD_AMM_PROGRAM_PUBKEY.as_ref().copied() +} + +#[inline(always)] +pub fn raydium_v4_program_pubkey() -> Option { + RAYDIUM_V4_PROGRAM_PUBKEY.as_ref().copied() +} + +#[cfg(test)] +mod tests { + use super::{ + jito_tip_pubkey, raydium_standard_amm_program_pubkey, raydium_v4_program_pubkey, + token_program_pubkey, wsol_pubkey, + }; + + #[test] + fn parses_all_cached_pubkeys() { + assert!(wsol_pubkey().is_some()); + assert!(token_program_pubkey().is_some()); + assert!(jito_tip_pubkey().is_some()); + assert!(raydium_standard_amm_program_pubkey().is_some()); + assert!(raydium_v4_program_pubkey().is_some()); + } +} diff --git a/src/slices/sniper/cpmm.rs b/src/slices/sniper/cpmm.rs new file mode 100644 index 0000000..bd942c1 --- /dev/null +++ b/src/slices/sniper/cpmm.rs @@ -0,0 +1,740 @@ +use std::{str::FromStr, sync::Arc}; + +use chrono::{Local, TimeZone}; +use solana_client::{ + nonblocking::rpc_client::RpcClient, + rpc_config::{RpcSendTransactionConfig, RpcTransactionConfig}, +}; +use solana_commitment_config::CommitmentConfig; +use solana_compute_budget_interface::ComputeBudgetInstruction; +use solana_sdk::{ + instruction::{AccountMeta, Instruction}, + pubkey::Pubkey, + signature::Signature, + signer::Signer, + transaction::Transaction, +}; +use solana_system_interface::instruction::transfer; +use solana_transaction_status::{ + EncodedConfirmedTransactionWithStatusMeta, EncodedTransaction, UiInstruction, UiMessage, + UiParsedInstruction, UiTransactionEncoding, +}; +use spl_associated_token_account::{ + get_associated_token_address, get_associated_token_address_with_program_id, + instruction::{create_associated_token_account, create_associated_token_account_idempotent}, +}; +use spl_token::instruction::{close_account, sync_native}; + +use crate::{ + MAX_RETRIES, + adapters::raydium::{ + RAYDIUM_STANDARD_AMM_PROGRAM_ID, STANDARD_AMM_SWAP_BASE_INPUT, WSOL_ADDRESS, pool_open_time, + }, + app::context::ExecutionContext, + domain::{ + aggregates::RuleBook, + events::{IngressMetadata, unix_timestamp_now_ns}, + services::RuleMatcher, + value_objects::{TxSubmissionMode, sol_amount::Lamports}, + }, + slices::sniper::{cache, log_parser::extract_u64_after_prefix}, +}; + +#[derive(Clone, Copy)] +struct CpmmAccounts<'account_data> { + deployer_address: &'account_data str, + amm_config: &'account_data str, + authority: &'account_data str, + pool_state: &'account_data str, + mint_a: &'account_data str, + mint_b: &'account_data str, + vault_a: &'account_data str, + vault_b: &'account_data str, + observation_state: &'account_data str, + token_program_a: &'account_data str, + token_program_b: &'account_data str, +} + +impl<'account_data> CpmmAccounts<'account_data> { + fn parse(accounts: &'account_data [String]) -> Option { + Some(Self { + deployer_address: accounts.first()?.as_str(), + amm_config: accounts.get(1)?.as_str(), + authority: accounts.get(2)?.as_str(), + pool_state: accounts.get(3)?.as_str(), + mint_a: accounts.get(4)?.as_str(), + mint_b: accounts.get(5)?.as_str(), + vault_a: accounts.get(10)?.as_str(), + vault_b: accounts.get(11)?.as_str(), + observation_state: accounts.get(13)?.as_str(), + token_program_a: accounts.get(15)?.as_str(), + token_program_b: accounts.get(16)?.as_str(), + }) + } + + fn token_address(&self) -> Option<&'account_data str> { + match (self.mint_a == WSOL_ADDRESS, self.mint_b == WSOL_ADDRESS) { + (true, false) => Some(self.mint_b), + (false, true) => Some(self.mint_a), + _ => None, + } + } + + fn token_program(&self) -> Option<&'account_data str> { + match (self.mint_a == WSOL_ADDRESS, self.mint_b == WSOL_ADDRESS) { + (true, false) => Some(self.token_program_b), + (false, true) => Some(self.token_program_a), + _ => None, + } + } + + fn token_is_vault_zero(&self) -> bool { + self.mint_a != WSOL_ADDRESS + } + + fn input_vault(&self) -> &'account_data str { + if self.token_is_vault_zero() { + self.vault_b + } else { + self.vault_a + } + } + + fn output_vault(&self) -> &'account_data str { + if self.token_is_vault_zero() { + self.vault_a + } else { + self.vault_b + } + } +} + +pub async fn handle_cpmm_event( + context: Arc, + rulebook: Arc, + logs: Vec, + signature: Signature, + ingress_metadata: IngressMetadata, +) { + let vault_0_amount = match extract_u64_after_prefix(&logs, "vault_0_amount:") { + Some(value) => value, + None => return, + }; + + let vault_1_amount = match extract_u64_after_prefix(&logs, "vault_1_amount:") { + Some(value) => value, + None => return, + }; + + log::debug!( + "CPMM > vault_0_amount: {}, vault_1_amount: {}", + vault_0_amount, + vault_1_amount + ); + + let ingress_latency_ns = + unix_timestamp_now_ns().saturating_sub(ingress_metadata.normalized_timestamp_ns); + log::debug!( + "CPMM > ingress source={}, normalized_ts={}ns, hw_ts={:?}, latency={}ns", + ingress_metadata.source.as_str(), + ingress_metadata.normalized_timestamp_ns, + ingress_metadata.hardware_timestamp_ns, + ingress_latency_ns + ); + + let creation_tx = + match fetch_transaction_with_retries(context.rpc.as_ref(), &signature, "CPMM").await { + Some(value) => value, + None => return, + }; + + log::debug!("CPMM > Pool creation transaction: {:?}", creation_tx); + + let accounts = match extract_program_accounts(&creation_tx, RAYDIUM_STANDARD_AMM_PROGRAM_ID) { + Some(value) => value, + None => return, + }; + + let parsed_accounts = match CpmmAccounts::parse(&accounts) { + Some(value) => value, + None => return, + }; + + log::debug!("CPMM > Pool creation accounts: {:?}", accounts); + + let token_address = match parsed_accounts.token_address() { + Some(value) => value, + None => return, + }; + let token_program = match parsed_accounts.token_program() { + Some(value) => value, + None => return, + }; + let deployer_address = parsed_accounts.deployer_address; + + let matched_rule = + match RuleMatcher::match_rule(rulebook.as_ref(), token_address, deployer_address) { + Some(value) => value, + None => { + log::debug!("CPMM > {} > Ignoring token", token_address); + return; + } + }; + + log::debug!( + "CPMM > {} > Matched by {:?} rule key {}", + token_address, + matched_rule.source, + matched_rule.cold.address + ); + + log::debug!( + "CPMM > {} > Snipe height: {} SOL, Jito tip: {} SOL, Slippage: {} %", + token_address, + matched_rule.hot.snipe_height().as_sol_string(), + matched_rule.hot.jito_tip().as_sol_string(), + matched_rule.hot.slippage().as_pct_string(), + ); + + log::info!("CPMM > Found token: {}", token_address); + log::info!("CPMM > {} > Creating transaction", token_address); + + let program_id = match cache::raydium_standard_amm_program_pubkey() { + Some(value) => value, + None => return, + }; + + let authority = match Pubkey::from_str(parsed_accounts.authority) { + Ok(value) => value, + Err(_) => return, + }; + + let amm_config = match Pubkey::from_str(parsed_accounts.amm_config) { + Ok(value) => value, + Err(_) => return, + }; + + let pool_state = match Pubkey::from_str(parsed_accounts.pool_state) { + Ok(value) => value, + Err(_) => return, + }; + + let input_vault = match Pubkey::from_str(parsed_accounts.input_vault()) { + Ok(value) => value, + Err(_) => return, + }; + + let output_vault = match Pubkey::from_str(parsed_accounts.output_vault()) { + Ok(value) => value, + Err(_) => return, + }; + + let observation_state = match Pubkey::from_str(parsed_accounts.observation_state) { + Ok(value) => value, + Err(_) => return, + }; + + log::debug!( + "CPMM > {} > Authority: {}, AMM config: {}, Pool state: {}, Input vault: {}, Output vault: {}, Observation state: {}", + token_address, + authority, + amm_config, + pool_state, + input_vault, + output_vault, + observation_state, + ); + + log::info!("CPMM > {} > Requesting pool data", token_address); + + let pool = match fetch_pool_with_retries(context.rpc.as_ref(), &pool_state, token_address).await + { + Some(value) => value, + None => return, + }; + + log::debug!("CPMM > {} > Pool response: {:?}", token_address, pool); + + let pool_value = match pool.value { + Some(value) => value, + None => return, + }; + + let pool_open_timestamp = match pool_open_time(&pool_value.data) { + Some(value) => value, + None => return, + }; + log::debug!( + "CPMM > {} > Pool open time: {}", + token_address, + pool_open_timestamp + ); + + let lamports = matched_rule.hot.snipe_height().as_lamports().as_u64(); + let wsol_pubkey = match cache::wsol_pubkey() { + Some(value) => value, + None => return, + }; + + let token_pubkey = match Pubkey::from_str(token_address) { + Ok(value) => value, + Err(_) => return, + }; + + let token_program_pubkey = match Pubkey::from_str(token_program) { + Ok(value) => value, + Err(_) => return, + }; + + let user_in_token_account = + get_associated_token_address(&context.keypair.pubkey(), &wsol_pubkey); + let user_out_token_account = get_associated_token_address_with_program_id( + &context.keypair.pubkey(), + &token_pubkey, + &token_program_pubkey, + ); + + let token_program_id = match cache::token_program_pubkey() { + Some(value) => value, + None => return, + }; + + let mut instructions = Vec::with_capacity(9); + instructions.push(ComputeBudgetInstruction::set_compute_unit_limit(120_000)); + instructions.push(ComputeBudgetInstruction::set_compute_unit_price( + context.priority_fees, + )); + + instructions.push(create_associated_token_account_idempotent( + &context.keypair.pubkey(), + &context.keypair.pubkey(), + &wsol_pubkey, + &token_program_id, + )); + + instructions.push(transfer( + &context.keypair.pubkey(), + &user_in_token_account, + lamports, + )); + + let sync_instruction = match sync_native(&spl_token::ID, &user_in_token_account) { + Ok(value) => value, + Err(error) => { + log::error!("CPMM > {} > sync_native failed: {}", token_address, error); + return; + } + }; + instructions.push(sync_instruction); + + instructions.push(create_associated_token_account( + &context.keypair.pubkey(), + &context.keypair.pubkey(), + &token_pubkey, + &token_program_pubkey, + )); + + let min_amount_out = calculate_min_amount_out( + lamports, + matched_rule.hot.slippage().as_bps(), + vault_0_amount, + vault_1_amount, + parsed_accounts.token_is_vault_zero(), + ); + + log::debug!( + "CPMM > {} > Min amount out: {}", + token_address, + min_amount_out + ); + + let mut swap_data = Vec::with_capacity(24); + swap_data.extend_from_slice(&STANDARD_AMM_SWAP_BASE_INPUT); + swap_data.extend_from_slice(&lamports.to_le_bytes()); + swap_data.extend_from_slice(&min_amount_out.to_le_bytes()); + + instructions.push(Instruction::new_with_bytes( + program_id, + &swap_data, + vec![ + AccountMeta::new_readonly(context.keypair.pubkey(), true), + AccountMeta::new_readonly(authority, false), + AccountMeta::new_readonly(amm_config, false), + AccountMeta::new(pool_state, false), + AccountMeta::new(user_in_token_account, false), + AccountMeta::new(user_out_token_account, false), + AccountMeta::new(input_vault, false), + AccountMeta::new(output_vault, false), + AccountMeta::new_readonly(token_program_id, false), + AccountMeta::new_readonly(token_program_pubkey, false), + AccountMeta::new_readonly(wsol_pubkey, false), + AccountMeta::new_readonly(token_pubkey, false), + AccountMeta::new(observation_state, false), + ], + )); + + let close_instruction = match close_account( + &token_program_id, + &user_in_token_account, + &context.keypair.pubkey(), + &context.keypair.pubkey(), + &[&context.keypair.pubkey()], + ) { + Ok(value) => value, + Err(error) => { + log::error!("CPMM > {} > close_account failed: {}", token_address, error); + return; + } + }; + instructions.push(close_instruction); + + let jito_tip_lamports = matched_rule.hot.jito_tip().as_lamports().as_u64(); + if context.tx_submission_mode == TxSubmissionMode::Jito { + let jito_tip_account = match cache::jito_tip_pubkey() { + Some(value) => value, + None => return, + }; + + instructions.push(transfer( + &context.keypair.pubkey(), + &jito_tip_account, + jito_tip_lamports, + )); + } + + maybe_wait_for_pool_open(pool_open_timestamp, token_address, "CPMM").await; + + let blockhash = match context.rpc.get_latest_blockhash().await { + Ok(value) => value, + Err(error) => { + log::error!( + "CPMM > {} > Failed to fetch blockhash: {}", + token_address, + error + ); + return; + } + }; + + let swap_tx = { + let signer_refs: [&dyn Signer; 1] = [context.keypair.as_ref()]; + Transaction::new_signed_with_payer( + &instructions, + Some(&context.keypair.pubkey()), + &signer_refs, + blockhash, + ) + }; + + log::info!("CPMM > {} > Starting swap", token_address); + + let sent_signature = match submit_swap_transaction(context.as_ref(), &swap_tx).await { + Ok(value) => value, + Err(error) => { + log::error!( + "CPMM > {} > Failed to send transaction: {}", + token_address, + error + ); + return; + } + }; + + log::info!( + "CPMM > {} > Swap transaction signature: {}", + token_address, + sent_signature + ); + + tokio::time::sleep(tokio::time::Duration::from_secs(60)).await; + + let status = match context.rpc.get_signature_status(&sent_signature).await { + Ok(value) => value, + Err(error) => { + log::error!( + "CPMM > {} > Signature status failed: {}", + token_address, + error + ); + return; + } + }; + + let Some(status) = status else { + log::error!("CPMM > {} > No signature status returned", token_address); + return; + }; + + if let Err(error) = status { + log::error!( + "CPMM > {} > Swap transaction failed: {}", + token_address, + error + ); + return; + } + + let balance = match context.rpc.get_balance(&context.keypair.pubkey()).await { + Ok(value) => value, + Err(error) => { + log::error!( + "CPMM > {} > Failed to fetch balance: {}", + token_address, + error + ); + return; + } + }; + + log::info!( + "CPMM > {} > Successfully swapped {} SOL with {} SOL tip budget (mode={})", + token_address, + matched_rule.hot.snipe_height().as_sol_string(), + matched_rule.hot.jito_tip().as_sol_string(), + context.tx_submission_mode.as_str(), + ); + log::info!( + "CPMM > {} > Balance: {} SOL", + token_address, + Lamports::new(balance).as_sol_string() + ); +} + +async fn submit_swap_transaction( + context: &ExecutionContext, + swap_tx: &Transaction, +) -> Result { + let send_config = RpcSendTransactionConfig { + skip_preflight: true, + encoding: Some(UiTransactionEncoding::Base58), + max_retries: Some(0), + ..RpcSendTransactionConfig::default() + }; + + if context.tx_submission_mode == TxSubmissionMode::Direct { + return context + .rpc + .send_transaction_with_config(swap_tx, send_config) + .await; + } + + let jito_rpc = RpcClient::new(context.jito_url.as_ref().clone()); + jito_rpc + .send_transaction_with_config(swap_tx, send_config) + .await +} + +async fn fetch_transaction_with_retries( + rpc: &RpcClient, + signature: &Signature, + label: &str, +) -> Option { + let mut retries = 0_usize; + + loop { + match rpc + .get_transaction_with_config( + signature, + RpcTransactionConfig { + commitment: Some(CommitmentConfig::confirmed()), + max_supported_transaction_version: Some(0), + encoding: Some(UiTransactionEncoding::JsonParsed), + }, + ) + .await + { + Ok(tx) => return Some(tx), + Err(error) => { + if !error.to_string().contains("invalid type: null") { + log::error!("{} > Error getting transaction: {}", label, error); + } else { + log::debug!("{} > Error getting transaction: {}", label, error); + } + + retries = retries.saturating_add(1); + if retries >= MAX_RETRIES { + log::error!( + "{} > Max retries reached in transaction. Exiting loop.", + label + ); + return None; + } + + tokio::time::sleep(tokio::time::Duration::from_millis(1_000)).await; + } + } + } +} + +async fn fetch_pool_with_retries( + rpc: &RpcClient, + pool_state: &Pubkey, + token_address: &str, +) -> Option>> { + let mut retries = 0_usize; + + loop { + match rpc + .get_account_with_commitment(pool_state, CommitmentConfig::confirmed()) + .await + { + Ok(pool) => { + if pool.value.is_none() { + log::debug!( + "CPMM > {} > Pool not available yet: {}", + token_address, + pool_state + ); + retries = retries.saturating_add(1); + if retries >= MAX_RETRIES { + log::error!("CPMM > Max retries reached in pool. Exiting loop."); + return None; + } + + tokio::time::sleep(tokio::time::Duration::from_millis(1_000)).await; + continue; + } + + return Some(pool); + } + Err(error) => { + if !error.to_string().contains("invalid type: null") { + log::error!("CPMM > Error getting pool data: {}", error); + } else { + log::debug!("CPMM > Error getting pool data: {}", error); + } + + retries = retries.saturating_add(1); + if retries >= MAX_RETRIES { + log::error!("CPMM > Max retries reached in pool. Exiting loop."); + return None; + } + + tokio::time::sleep(tokio::time::Duration::from_millis(1_000)).await; + } + } + } +} + +fn extract_program_accounts( + tx: &EncodedConfirmedTransactionWithStatusMeta, + program_id: &str, +) -> Option> { + let EncodedTransaction::Json(json_tx) = &tx.transaction.transaction else { + return None; + }; + + let UiMessage::Parsed(message) = &json_tx.message else { + return None; + }; + + for instruction in &message.instructions { + let UiInstruction::Parsed(parsed_instruction) = instruction else { + continue; + }; + + let UiParsedInstruction::PartiallyDecoded(decoded_instruction) = parsed_instruction else { + continue; + }; + + if decoded_instruction.program_id == program_id { + return Some(decoded_instruction.accounts.clone()); + } + } + + None +} + +#[inline(always)] +fn calculate_min_amount_out( + lamports: u64, + slippage_bps: u16, + vault_0_amount: u64, + vault_1_amount: u64, + token_is_vault_zero: bool, +) -> u64 { + if vault_0_amount == 0 || vault_1_amount == 0 { + return 0; + } + + if slippage_bps >= 10_000 { + return 0; + } + + let lamports_u128 = u128::from(lamports); + let max_amount_out = if token_is_vault_zero { + lamports_u128 + .checked_mul(u128::from(vault_0_amount)) + .and_then(|value| value.checked_div(u128::from(vault_1_amount))) + } else { + lamports_u128 + .checked_mul(u128::from(vault_1_amount)) + .and_then(|value| value.checked_div(u128::from(vault_0_amount))) + }; + + let remaining_bps = 10_000_u128.saturating_sub(u128::from(slippage_bps)); + let min_amount_out = max_amount_out + .and_then(|value| value.checked_mul(remaining_bps)) + .and_then(|value| value.checked_div(10_000_u128)); + + min_amount_out + .and_then(|value| u64::try_from(value).ok()) + .unwrap_or(u64::MAX) +} + +async fn maybe_wait_for_pool_open(pool_open_time: u64, token_address: &str, label: &str) { + let now = Local::now(); + + let Some(target_time) = Local.timestamp_opt(pool_open_time as i64, 0).single() else { + return; + }; + + if now >= target_time { + return; + } + + let duration = target_time.signed_duration_since(now); + let remaining_minutes = duration.num_minutes(); + let remaining_seconds = duration + .num_seconds() + .saturating_sub(remaining_minutes.saturating_mul(60)); + + log::info!( + "{} > {} > Pool closed. Proceeding with snipe in {}m {}s. UTC: {}", + label, + token_address, + remaining_minutes, + remaining_seconds, + target_time.to_rfc2822(), + ); + + if let Ok(duration) = duration.to_std() { + tokio::time::sleep(duration).await; + } +} + +#[cfg(test)] +mod tests { + use super::calculate_min_amount_out; + + #[test] + fn min_amount_out_uses_integer_fixed_point_math() { + let min = calculate_min_amount_out(1_000, 100, 5_000, 10_000, true); + assert_eq!(min, 495); + } + + #[test] + fn min_amount_out_returns_zero_for_invalid_bounds() { + assert_eq!(calculate_min_amount_out(1_000, 0, 0, 10_000, true), 0); + assert_eq!( + calculate_min_amount_out(1_000, 10_000, 5_000, 10_000, true), + 0 + ); + } + + #[test] + fn min_amount_out_saturates_on_internal_overflow() { + let min = calculate_min_amount_out(u64::MAX, 1, u64::MAX, 1, true); + assert_eq!(min, u64::MAX); + } +} diff --git a/src/slices/sniper/engine.rs b/src/slices/sniper/engine.rs new file mode 100644 index 0000000..8e6f665 --- /dev/null +++ b/src/slices/sniper/engine.rs @@ -0,0 +1,126 @@ +use std::{str::FromStr, sync::Arc, time::Instant}; + +use solana_sdk::signature::Signature; +use tokio::sync::{mpsc, watch}; + +use crate::{ + app::context::ExecutionContext, + domain::{ + aggregates::RuleBook, + events::{RawLogEvent, unix_timestamp_now_ns}, + }, +}; + +use super::{ + cpmm, openbook, + pool_filter::{is_cpmm_candidate_logs, is_openbook_candidate_logs}, + telemetry::LatencyTelemetry, +}; + +pub struct SniperEngine { + context: Arc, + events_rx: mpsc::UnboundedReceiver, + rulebook_rx: watch::Receiver>, + telemetry: Arc, +} + +impl SniperEngine { + #[expect( + clippy::missing_const_for_fn, + reason = "runtime initialization with channels and Arcs" + )] + pub fn new( + context: Arc, + events_rx: mpsc::UnboundedReceiver, + rulebook_rx: watch::Receiver>, + telemetry: Arc, + ) -> Self { + Self { + context, + events_rx, + rulebook_rx, + telemetry, + } + } + + pub async fn run(mut self) { + while let Some(event) = self.events_rx.recv().await { + let context = Arc::clone(&self.context); + let rulebook = self.rulebook_rx.borrow().clone(); + let telemetry = Arc::clone(&self.telemetry); + let ingress_to_engine_ns = + unix_timestamp_now_ns().saturating_sub(event.ingress.normalized_timestamp_ns); + self.telemetry + .record("ingress_to_engine_ns", ingress_to_engine_ns); + + tokio::spawn(async move { + handle_event(context, rulebook, event, telemetry).await; + }); + } + + log::warn!("Log event channel closed. Sniper engine stopped."); + } +} + +async fn handle_event( + context: Arc, + rulebook: Arc, + event: RawLogEvent, + telemetry: Arc, +) { + let classify_started_at = Instant::now(); + + if event.has_error { + telemetry.record( + "engine_classification_ns", + elapsed_ns_u64(classify_started_at.elapsed()), + ); + return; + } + + let signature = match Signature::from_str(&event.signature) { + Ok(value) => value, + Err(error) => { + log::debug!("Invalid signature in log event: {}", error); + telemetry.record( + "engine_classification_ns", + elapsed_ns_u64(classify_started_at.elapsed()), + ); + return; + } + }; + + let dispatch_started_at = Instant::now(); + let ingress_metadata = event.ingress; + let logs = event.logs; + + if is_cpmm_candidate_logs(&logs) { + cpmm::handle_cpmm_event(context, rulebook, logs, signature, ingress_metadata).await; + telemetry.record( + "strategy_dispatch_ns", + elapsed_ns_u64(dispatch_started_at.elapsed()), + ); + telemetry.record( + "engine_classification_ns", + elapsed_ns_u64(classify_started_at.elapsed()), + ); + return; + } + + if is_openbook_candidate_logs(&logs) { + openbook::handle_openbook_event(context, rulebook, logs, signature, ingress_metadata).await; + telemetry.record( + "strategy_dispatch_ns", + elapsed_ns_u64(dispatch_started_at.elapsed()), + ); + } + + telemetry.record( + "engine_classification_ns", + elapsed_ns_u64(classify_started_at.elapsed()), + ); +} + +fn elapsed_ns_u64(duration: std::time::Duration) -> u64 { + u64::try_from(duration.as_nanos()).unwrap_or(u64::MAX) +} diff --git a/src/slices/sniper/log_parser.rs b/src/slices/sniper/log_parser.rs new file mode 100644 index 0000000..eca7c0d --- /dev/null +++ b/src/slices/sniper/log_parser.rs @@ -0,0 +1,91 @@ +#[inline(always)] +pub fn extract_u64_after_prefix(logs: &[String], prefix: &str) -> Option { + logs.iter() + .find_map(|log| extract_u64_from_line(log, prefix)) +} + +#[inline(always)] +pub fn extract_i64_after_prefix(logs: &[String], prefix: &str) -> Option { + logs.iter() + .find_map(|log| extract_i64_from_line(log, prefix)) +} + +#[inline(always)] +fn extract_u64_from_line(log: &str, prefix: &str) -> Option { + let prefix_start = log.find(prefix)?; + let value_start = prefix_start.checked_add(prefix.len())?; + let value_slice = log.get(value_start..)?; + parse_ascii_u64_prefix(value_slice) +} + +#[inline(always)] +fn extract_i64_from_line(log: &str, prefix: &str) -> Option { + let prefix_start = log.find(prefix)?; + let value_start = prefix_start.checked_add(prefix.len())?; + let value_slice = log.get(value_start..)?; + + if let Some(unsigned_slice) = value_slice.strip_prefix('-') { + let unsigned_value = parse_ascii_u64_prefix(unsigned_slice)?; + let signed_value = i64::try_from(unsigned_value).ok()?; + return signed_value.checked_neg(); + } + + let unsigned_value = parse_ascii_u64_prefix(value_slice)?; + i64::try_from(unsigned_value).ok() +} + +#[inline(always)] +fn parse_ascii_u64_prefix(value: &str) -> Option { + let mut result = 0_u64; + let mut parsed_digit = false; + + for byte in value.bytes() { + if !byte.is_ascii_digit() { + break; + } + + parsed_digit = true; + result = result + .checked_mul(10)? + .checked_add(u64::from(byte.saturating_sub(b'0')))?; + } + + if parsed_digit { Some(result) } else { None } +} + +#[cfg(test)] +mod tests { + use super::{extract_i64_after_prefix, extract_u64_after_prefix}; + + #[test] + fn extracts_unsigned_value() { + let logs = vec![ + "Program log: unrelated".to_owned(), + "Program log: vault_0_amount:12345, vault_1_amount:67890".to_owned(), + ]; + + assert_eq!( + extract_u64_after_prefix(&logs, "vault_0_amount:"), + Some(12_345) + ); + assert_eq!( + extract_u64_after_prefix(&logs, "vault_1_amount:"), + Some(67_890) + ); + } + + #[test] + fn extracts_signed_value() { + let logs = vec!["Program log: open_time: -42, slot: 7".to_owned()]; + + assert_eq!(extract_i64_after_prefix(&logs, "open_time: "), Some(-42)); + } + + #[test] + fn returns_none_when_prefix_or_digits_missing() { + let logs = vec!["Program log: open_time: n/a".to_owned()]; + + assert_eq!(extract_u64_after_prefix(&logs, "open_time: "), None); + assert_eq!(extract_i64_after_prefix(&logs, "missing: "), None); + } +} diff --git a/src/slices/sniper/mod.rs b/src/slices/sniper/mod.rs new file mode 100644 index 0000000..7f88e96 --- /dev/null +++ b/src/slices/sniper/mod.rs @@ -0,0 +1,8 @@ +pub mod cache; +pub mod cpmm; +pub mod engine; +pub mod log_parser; +pub mod openbook; +pub mod pool_filter; +pub mod replay; +pub mod telemetry; diff --git a/src/slices/sniper/openbook.rs b/src/slices/sniper/openbook.rs new file mode 100644 index 0000000..ffeb98c --- /dev/null +++ b/src/slices/sniper/openbook.rs @@ -0,0 +1,667 @@ +use std::{str::FromStr, sync::Arc}; + +use chrono::{Local, TimeZone}; +use solana_client::{ + nonblocking::rpc_client::RpcClient, + rpc_config::{RpcSendTransactionConfig, RpcTransactionConfig}, +}; +use solana_commitment_config::CommitmentConfig; +use solana_compute_budget_interface::ComputeBudgetInstruction; +use solana_sdk::{ + instruction::{AccountMeta, Instruction}, + pubkey::Pubkey, + signature::Signature, + signer::Signer, + transaction::Transaction, +}; +use solana_system_interface::instruction::transfer; +use solana_transaction_status::{ + EncodedConfirmedTransactionWithStatusMeta, EncodedTransaction, UiInstruction, UiMessage, + UiParsedInstruction, UiTransactionEncoding, +}; +use spl_associated_token_account::{ + get_associated_token_address, + instruction::{create_associated_token_account, create_associated_token_account_idempotent}, +}; +use spl_token::instruction::{close_account, sync_native}; + +use crate::{ + MAX_RETRIES, + adapters::raydium::{ + RAYDIUM_V4_PROGRAM_ID, SwapInstructionBaseIn, WSOL_ADDRESS, get_associated_authority, + get_market_accounts, + }, + app::context::ExecutionContext, + domain::{ + aggregates::RuleBook, + events::{IngressMetadata, unix_timestamp_now_ns}, + services::RuleMatcher, + value_objects::{TxSubmissionMode, sol_amount::Lamports}, + }, + slices::sniper::{ + cache, + log_parser::{extract_i64_after_prefix, extract_u64_after_prefix}, + }, +}; + +#[derive(Clone, Copy)] +struct OpenbookAccounts<'account_data> { + id: &'account_data str, + authority: &'account_data str, + open_orders: &'account_data str, + mint_a: &'account_data str, + mint_b: &'account_data str, + base_vault: &'account_data str, + quote_vault: &'account_data str, + target_orders: &'account_data str, + market_program_id: &'account_data str, + market_id: &'account_data str, + deployer_address: &'account_data str, +} + +impl<'account_data> OpenbookAccounts<'account_data> { + fn parse(accounts: &'account_data [String]) -> Option { + Some(Self { + id: accounts.get(4)?.as_str(), + authority: accounts.get(5)?.as_str(), + open_orders: accounts.get(6)?.as_str(), + mint_a: accounts.get(8)?.as_str(), + mint_b: accounts.get(9)?.as_str(), + base_vault: accounts.get(10)?.as_str(), + quote_vault: accounts.get(11)?.as_str(), + target_orders: accounts.get(12)?.as_str(), + market_program_id: accounts.get(15)?.as_str(), + market_id: accounts.get(16)?.as_str(), + deployer_address: accounts.get(17)?.as_str(), + }) + } + + fn token_address(&self) -> Option<&'account_data str> { + match (self.mint_a == WSOL_ADDRESS, self.mint_b == WSOL_ADDRESS) { + (true, false) => Some(self.mint_b), + (false, true) => Some(self.mint_a), + _ => None, + } + } + + fn token_is_coin_mint(&self) -> bool { + self.mint_a != WSOL_ADDRESS + } +} + +pub async fn handle_openbook_event( + context: Arc, + rulebook: Arc, + logs: Vec, + signature: Signature, + ingress_metadata: IngressMetadata, +) { + let init_pc_amount = match extract_u64_after_prefix(&logs, "init_pc_amount: ") { + Some(value) => value, + None => return, + }; + + let init_coin_amount = match extract_u64_after_prefix(&logs, "init_coin_amount: ") { + Some(value) => value, + None => return, + }; + + let open_timestamp = match extract_i64_after_prefix(&logs, "open_time: ") { + Some(value) => value, + None => return, + }; + + log::debug!( + "OpenBook > init_pc_amount: {}, init_coin_amount: {}, open_time: {}", + init_pc_amount, + init_coin_amount, + open_timestamp + ); + + let ingress_latency_ns = + unix_timestamp_now_ns().saturating_sub(ingress_metadata.normalized_timestamp_ns); + log::debug!( + "OpenBook > ingress source={}, normalized_ts={}ns, hw_ts={:?}, latency={}ns", + ingress_metadata.source.as_str(), + ingress_metadata.normalized_timestamp_ns, + ingress_metadata.hardware_timestamp_ns, + ingress_latency_ns + ); + + let creation_tx = + match fetch_transaction_with_retries(context.rpc.as_ref(), &signature, "OpenBook").await { + Some(value) => value, + None => return, + }; + + log::debug!("OpenBook > Pool creation transaction: {:?}", creation_tx); + + let accounts = match extract_program_accounts(&creation_tx, RAYDIUM_V4_PROGRAM_ID) { + Some(value) => value, + None => return, + }; + let parsed_accounts = match OpenbookAccounts::parse(&accounts) { + Some(value) => value, + None => return, + }; + + log::debug!("OpenBook > Pool creation accounts: {:?}", accounts); + + let token_address = match parsed_accounts.token_address() { + Some(value) => value, + None => return, + }; + + let deployer_address = parsed_accounts.deployer_address; + + let matched_rule = + match RuleMatcher::match_rule(rulebook.as_ref(), token_address, deployer_address) { + Some(value) => value, + None => { + log::debug!("OpenBook > {} > Ignoring token", token_address); + return; + } + }; + + log::debug!( + "OpenBook > {} > Matched by {:?} rule key {}", + token_address, + matched_rule.source, + matched_rule.cold.address + ); + + log::debug!( + "OpenBook > {} > Snipe height: {} SOL, Jito tip: {} SOL, Slippage: {} %", + token_address, + matched_rule.hot.snipe_height().as_sol_string(), + matched_rule.hot.jito_tip().as_sol_string(), + matched_rule.hot.slippage().as_pct_string() + ); + + log::info!("OpenBook > {} > Found token", token_address); + + let id = match Pubkey::from_str(parsed_accounts.id) { + Ok(value) => value, + Err(_) => return, + }; + let authority = match Pubkey::from_str(parsed_accounts.authority) { + Ok(value) => value, + Err(_) => return, + }; + let open_orders = match Pubkey::from_str(parsed_accounts.open_orders) { + Ok(value) => value, + Err(_) => return, + }; + let base_vault = match Pubkey::from_str(parsed_accounts.base_vault) { + Ok(value) => value, + Err(_) => return, + }; + let quote_vault = match Pubkey::from_str(parsed_accounts.quote_vault) { + Ok(value) => value, + Err(_) => return, + }; + let target_orders = match Pubkey::from_str(parsed_accounts.target_orders) { + Ok(value) => value, + Err(_) => return, + }; + let market_program_id = match Pubkey::from_str(parsed_accounts.market_program_id) { + Ok(value) => value, + Err(_) => return, + }; + let market_id = match Pubkey::from_str(parsed_accounts.market_id) { + Ok(value) => value, + Err(_) => return, + }; + + log::debug!( + "OpenBook > {} > ID: {}, Authority: {}, Open orders: {}, Base vault: {}, Quote vault: {}, Target orders: {}, Market program ID: {}, Market ID: {}", + token_address, + id, + authority, + open_orders, + base_vault, + quote_vault, + target_orders, + market_program_id, + market_id, + ); + + let market = match get_market_accounts(&context.rpc, &market_id).await { + Some(value) => value, + None => return, + }; + + let lamports = matched_rule.hot.snipe_height().as_lamports().as_u64(); + + let wsol_pubkey = match cache::wsol_pubkey() { + Some(value) => value, + None => return, + }; + + let token_pubkey = match Pubkey::from_str(token_address) { + Ok(value) => value, + Err(_) => return, + }; + + let token_program_id = match cache::token_program_pubkey() { + Some(value) => value, + None => return, + }; + + let user_in_token_account = + get_associated_token_address(&context.keypair.pubkey(), &wsol_pubkey); + let user_out_token_account = + get_associated_token_address(&context.keypair.pubkey(), &token_pubkey); + + let mut instructions = Vec::with_capacity(9); + + instructions.push(ComputeBudgetInstruction::set_compute_unit_limit(120_000)); + instructions.push(ComputeBudgetInstruction::set_compute_unit_price( + context.priority_fees, + )); + + instructions.push(create_associated_token_account_idempotent( + &context.keypair.pubkey(), + &context.keypair.pubkey(), + &wsol_pubkey, + &token_program_id, + )); + + instructions.push(transfer( + &context.keypair.pubkey(), + &user_in_token_account, + lamports, + )); + + let sync_instruction = match sync_native(&spl_token::ID, &user_in_token_account) { + Ok(value) => value, + Err(error) => { + log::error!( + "OpenBook > {} > sync_native failed: {}", + token_address, + error + ); + return; + } + }; + instructions.push(sync_instruction); + + instructions.push(create_associated_token_account( + &context.keypair.pubkey(), + &context.keypair.pubkey(), + &token_pubkey, + &token_program_id, + )); + + let min_amount_out = calculate_min_amount_out( + lamports, + matched_rule.hot.slippage().as_bps(), + init_pc_amount, + init_coin_amount, + parsed_accounts.token_is_coin_mint(), + ); + + log::debug!( + "OpenBook > {} > Min amount out: {}", + token_address, + min_amount_out + ); + + let market_authority = + match get_associated_authority(&market.program_id, &market.state.own_address) { + Ok(value) => value.0, + Err(_) => return, + }; + + let swap_instruction = Instruction::new_with_borsh( + match cache::raydium_v4_program_pubkey() { + Some(value) => value, + None => return, + }, + &SwapInstructionBaseIn { + discriminator: 9, + amount_in: lamports, + minimum_amount_out: min_amount_out, + }, + vec![ + AccountMeta::new_readonly(token_program_id, false), + AccountMeta::new(id, false), + AccountMeta::new_readonly(authority, false), + AccountMeta::new(open_orders, false), + AccountMeta::new(target_orders, false), + AccountMeta::new(base_vault, false), + AccountMeta::new(quote_vault, false), + AccountMeta::new_readonly(market_program_id, false), + AccountMeta::new(market_id, false), + AccountMeta::new(market.state.bids, false), + AccountMeta::new(market.state.asks, false), + AccountMeta::new(market.state.event_queue, false), + AccountMeta::new(market.state.base_vault, false), + AccountMeta::new(market.state.quote_vault, false), + AccountMeta::new_readonly(market_authority, false), + AccountMeta::new(user_in_token_account, false), + AccountMeta::new(user_out_token_account, false), + AccountMeta::new_readonly(context.keypair.pubkey(), true), + ], + ); + instructions.push(swap_instruction); + + let close_instruction = match close_account( + &token_program_id, + &user_in_token_account, + &context.keypair.pubkey(), + &context.keypair.pubkey(), + &[&context.keypair.pubkey()], + ) { + Ok(value) => value, + Err(error) => { + log::error!( + "OpenBook > {} > close_account failed: {}", + token_address, + error + ); + return; + } + }; + instructions.push(close_instruction); + + let jito_tip_lamports = matched_rule.hot.jito_tip().as_lamports().as_u64(); + if context.tx_submission_mode == TxSubmissionMode::Jito { + let jito_tip_account = match cache::jito_tip_pubkey() { + Some(value) => value, + None => return, + }; + + instructions.push(transfer( + &context.keypair.pubkey(), + &jito_tip_account, + jito_tip_lamports, + )); + } + + maybe_wait_for_pool_open(open_timestamp, token_address, "OpenBook").await; + + let blockhash = match context.rpc.get_latest_blockhash().await { + Ok(value) => value, + Err(error) => { + log::error!( + "OpenBook > {} > Failed to fetch blockhash: {}", + token_address, + error + ); + return; + } + }; + + let swap_tx = { + let signer_refs: [&dyn Signer; 1] = [context.keypair.as_ref()]; + Transaction::new_signed_with_payer( + &instructions, + Some(&context.keypair.pubkey()), + &signer_refs, + blockhash, + ) + }; + + let sent_signature = match submit_swap_transaction(context.as_ref(), &swap_tx).await { + Ok(value) => value, + Err(error) => { + log::error!( + "OpenBook > {} > Failed to send transaction: {}", + token_address, + error + ); + return; + } + }; + + log::info!( + "OpenBook > {} > Swap transaction signature: {}", + token_address, + sent_signature + ); + + tokio::time::sleep(tokio::time::Duration::from_secs(60)).await; + + let status = match context.rpc.get_signature_status(&sent_signature).await { + Ok(value) => value, + Err(error) => { + log::error!( + "OpenBook > {} > Signature status failed: {}", + token_address, + error + ); + return; + } + }; + + let Some(status) = status else { + log::error!( + "OpenBook > {} > No signature status returned", + token_address + ); + return; + }; + + if let Err(error) = status { + log::error!( + "OpenBook > {} > Swap transaction failed: {}", + token_address, + error + ); + return; + } + + let balance = match context.rpc.get_balance(&context.keypair.pubkey()).await { + Ok(value) => value, + Err(error) => { + log::error!( + "OpenBook > {} > Failed to fetch balance: {}", + token_address, + error + ); + return; + } + }; + + log::info!( + "OpenBook > {} > Successfully swapped {} SOL with {} SOL tip budget (mode={})", + token_address, + matched_rule.hot.snipe_height().as_sol_string(), + matched_rule.hot.jito_tip().as_sol_string(), + context.tx_submission_mode.as_str(), + ); + log::info!( + "OpenBook > {} > Balance: {} SOL", + token_address, + Lamports::new(balance).as_sol_string() + ); +} + +async fn submit_swap_transaction( + context: &ExecutionContext, + swap_tx: &Transaction, +) -> Result { + let send_config = RpcSendTransactionConfig { + skip_preflight: true, + encoding: Some(UiTransactionEncoding::Base58), + max_retries: Some(0), + ..RpcSendTransactionConfig::default() + }; + + if context.tx_submission_mode == TxSubmissionMode::Direct { + return context + .rpc + .send_transaction_with_config(swap_tx, send_config) + .await; + } + + let jito_rpc = RpcClient::new(context.jito_url.as_ref().clone()); + jito_rpc + .send_transaction_with_config(swap_tx, send_config) + .await +} + +async fn fetch_transaction_with_retries( + rpc: &RpcClient, + signature: &Signature, + label: &str, +) -> Option { + let mut retries = 0_usize; + + loop { + match rpc + .get_transaction_with_config( + signature, + RpcTransactionConfig { + commitment: Some(CommitmentConfig::confirmed()), + max_supported_transaction_version: Some(0), + encoding: Some(UiTransactionEncoding::JsonParsed), + }, + ) + .await + { + Ok(tx) => return Some(tx), + Err(error) => { + if !error.to_string().contains("invalid type: null") { + log::error!("{} > Error getting transaction: {}", label, error); + } else { + log::debug!("{} > Error getting transaction: {}", label, error); + } + + retries = retries.saturating_add(1); + if retries >= MAX_RETRIES { + log::error!( + "{} > Max retries reached in transaction. Exiting loop.", + label + ); + return None; + } + + tokio::time::sleep(tokio::time::Duration::from_millis(1_000)).await; + } + } + } +} + +fn extract_program_accounts( + tx: &EncodedConfirmedTransactionWithStatusMeta, + program_id: &str, +) -> Option> { + let EncodedTransaction::Json(json_tx) = &tx.transaction.transaction else { + return None; + }; + + let UiMessage::Parsed(message) = &json_tx.message else { + return None; + }; + + for instruction in &message.instructions { + let UiInstruction::Parsed(parsed_instruction) = instruction else { + continue; + }; + + let UiParsedInstruction::PartiallyDecoded(decoded_instruction) = parsed_instruction else { + continue; + }; + + if decoded_instruction.program_id == program_id { + return Some(decoded_instruction.accounts.clone()); + } + } + + None +} + +#[inline(always)] +fn calculate_min_amount_out( + lamports: u64, + slippage_bps: u16, + init_pc_amount: u64, + init_coin_amount: u64, + token_is_coin_mint: bool, +) -> u64 { + if init_pc_amount == 0 || init_coin_amount == 0 { + return 0; + } + + if slippage_bps >= 10_000 { + return 0; + } + + let lamports_u128 = u128::from(lamports); + let max_amount_out = if token_is_coin_mint { + lamports_u128 + .checked_mul(u128::from(init_coin_amount)) + .and_then(|value| value.checked_div(u128::from(init_pc_amount))) + } else { + lamports_u128 + .checked_mul(u128::from(init_pc_amount)) + .and_then(|value| value.checked_div(u128::from(init_coin_amount))) + }; + + let remaining_bps = 10_000_u128.saturating_sub(u128::from(slippage_bps)); + let min_amount_out = max_amount_out + .and_then(|value| value.checked_mul(remaining_bps)) + .and_then(|value| value.checked_div(10_000_u128)); + + min_amount_out + .and_then(|value| u64::try_from(value).ok()) + .unwrap_or(u64::MAX) +} + +async fn maybe_wait_for_pool_open(open_timestamp: i64, token_address: &str, label: &str) { + let now = Local::now(); + let Some(target_time) = Local.timestamp_opt(open_timestamp, 0).single() else { + return; + }; + + if now >= target_time { + return; + } + + let duration = target_time.signed_duration_since(now); + let remaining_minutes = duration.num_minutes(); + let remaining_seconds = duration + .num_seconds() + .saturating_sub(remaining_minutes.saturating_mul(60)); + + log::info!( + "{} > {} > Pool closed. Proceeding with snipe in {}m {}s. UTC: {}", + label, + token_address, + remaining_minutes, + remaining_seconds, + target_time.to_rfc2822(), + ); + + if let Ok(duration) = duration.to_std() { + tokio::time::sleep(duration).await; + } +} + +#[cfg(test)] +mod tests { + use super::calculate_min_amount_out; + + #[test] + fn min_amount_out_uses_integer_fixed_point_math() { + let min = calculate_min_amount_out(1_000, 100, 20_000, 10_000, true); + assert_eq!(min, 495); + } + + #[test] + fn min_amount_out_returns_zero_for_invalid_bounds() { + assert_eq!(calculate_min_amount_out(1_000, 0, 0, 10_000, true), 0); + assert_eq!( + calculate_min_amount_out(1_000, 10_000, 20_000, 10_000, true), + 0 + ); + } + + #[test] + fn min_amount_out_saturates_on_internal_overflow() { + let min = calculate_min_amount_out(u64::MAX, 1, u64::MAX, 1, false); + assert_eq!(min, u64::MAX); + } +} diff --git a/src/slices/sniper/pool_filter.rs b/src/slices/sniper/pool_filter.rs new file mode 100644 index 0000000..1ecf3ce --- /dev/null +++ b/src/slices/sniper/pool_filter.rs @@ -0,0 +1,84 @@ +use crate::adapters::raydium::{RAYDIUM_STANDARD_AMM_PROGRAM_ID, RAYDIUM_V4_PROGRAM_ID}; + +const CPMM_EXCLUSION_MARKERS: [&str; 6] = [ + "SwapBaseIn", + "SwapBaseOutput", + "CollectProtocolFee", + "Deposit", + "CollectFundFee", + "Burn", +]; + +#[inline(always)] +pub fn is_cpmm_candidate_logs(logs: &[String]) -> bool { + logs.iter() + .any(|line| line.contains(RAYDIUM_STANDARD_AMM_PROGRAM_ID)) + && !logs.iter().any(|line| { + CPMM_EXCLUSION_MARKERS + .iter() + .any(|marker| line.contains(marker)) + }) +} + +#[inline(always)] +pub fn is_openbook_candidate_logs(logs: &[String]) -> bool { + logs.iter().any(|line| line.contains(RAYDIUM_V4_PROGRAM_ID)) + && logs.iter().any(|line| line.contains("initialize2")) +} + +#[inline(always)] +pub fn is_pool_creation_candidate_logs(logs: &[String]) -> bool { + is_cpmm_candidate_logs(logs) || is_openbook_candidate_logs(logs) +} + +#[inline(always)] +pub fn is_pool_creation_dma_payload(payload: &[u8]) -> bool { + let cpmm_hit = payload_contains(payload, RAYDIUM_STANDARD_AMM_PROGRAM_ID.as_bytes()); + let openbook_hit = payload_contains(payload, RAYDIUM_V4_PROGRAM_ID.as_bytes()) + && payload_contains(payload, b"initialize2"); + + if openbook_hit { + return true; + } + + if !cpmm_hit { + return false; + } + + !CPMM_EXCLUSION_MARKERS + .iter() + .any(|marker| payload_contains(payload, marker.as_bytes())) +} + +#[inline(always)] +fn payload_contains(payload: &[u8], needle: &[u8]) -> bool { + if needle.is_empty() { + return true; + } + + payload.windows(needle.len()).any(|window| window == needle) +} + +#[cfg(test)] +mod tests { + use super::{is_pool_creation_candidate_logs, is_pool_creation_dma_payload}; + use crate::adapters::raydium::RAYDIUM_V4_PROGRAM_ID; + + #[test] + fn matches_openbook_logs() { + let logs = vec![ + format!("Program {} invoke [1]", RAYDIUM_V4_PROGRAM_ID), + "Program log: initialize2".to_owned(), + ]; + assert!(is_pool_creation_candidate_logs(&logs)); + } + + #[test] + fn matches_openbook_dma_payload() { + let payload = format!( + "log=Program {}\nlog=Program log: initialize2", + RAYDIUM_V4_PROGRAM_ID + ); + assert!(is_pool_creation_dma_payload(payload.as_bytes())); + } +} diff --git a/src/slices/sniper/replay.rs b/src/slices/sniper/replay.rs new file mode 100644 index 0000000..9f6e718 --- /dev/null +++ b/src/slices/sniper/replay.rs @@ -0,0 +1,255 @@ +use std::time::Instant; + +use crate::{ + adapters::raydium::{RAYDIUM_STANDARD_AMM_PROGRAM_ID, RAYDIUM_V4_PROGRAM_ID}, + domain::events::{ + IngressMetadata, IngressSource, RawLogEvent, normalize_hardware_timestamp_ns, + unix_timestamp_now_ns, + }, +}; + +use super::pool_filter::{is_pool_creation_candidate_logs, is_pool_creation_dma_payload}; + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct ReplayPathStats { + pub path: &'static str, + pub total_events: usize, + pub candidate_events: usize, + pub elapsed_ns: u64, + pub throughput_events_per_sec: u64, + pub p50_ns: u64, + pub p99_ns: u64, + pub max_ns: u64, +} + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct ReplayBenchmarkReport { + pub event_count: usize, + pub burst_size: usize, + pub fpga_path: ReplayPathStats, + pub kernel_bypass_path: ReplayPathStats, +} + +pub fn run_synthetic_replay(event_count: usize, burst_size: usize) -> ReplayBenchmarkReport { + let total_events = event_count.max(1); + let burst = burst_size.max(1); + let synthetic = build_synthetic_dataset(total_events); + + let fpga_path = benchmark_fpga_path(&synthetic, burst); + let kernel_bypass_path = benchmark_kernel_path(&synthetic, burst); + + ReplayBenchmarkReport { + event_count: total_events, + burst_size: burst, + fpga_path, + kernel_bypass_path, + } +} + +pub fn log_replay_report(report: &ReplayBenchmarkReport) { + log::info!( + "Replay benchmark > events={} burst={}", + report.event_count, + report.burst_size + ); + log::info!( + "Replay benchmark > path={} candidates={} throughput={}ev/s p50={}ns p99={}ns max={}ns", + report.fpga_path.path, + report.fpga_path.candidate_events, + report.fpga_path.throughput_events_per_sec, + report.fpga_path.p50_ns, + report.fpga_path.p99_ns, + report.fpga_path.max_ns + ); + log::info!( + "Replay benchmark > path={} candidates={} throughput={}ev/s p50={}ns p99={}ns max={}ns", + report.kernel_bypass_path.path, + report.kernel_bypass_path.candidate_events, + report.kernel_bypass_path.throughput_events_per_sec, + report.kernel_bypass_path.p50_ns, + report.kernel_bypass_path.p99_ns, + report.kernel_bypass_path.max_ns + ); +} + +#[derive(Clone, Debug)] +struct SyntheticEvent { + kernel_event: RawLogEvent, + dma_payload: Vec, +} + +fn build_synthetic_dataset(total_events: usize) -> Vec { + let mut dataset = Vec::with_capacity(total_events); + for index in 0..total_events { + let signature = format!("synthetic_sig_{index}"); + let logs = synthetic_logs(index); + let payload = synthetic_dma_payload(&signature, &logs); + let receive_timestamp_ns = unix_timestamp_now_ns(); + let normalized_timestamp_ns = normalize_hardware_timestamp_ns(None, receive_timestamp_ns); + + dataset.push(SyntheticEvent { + kernel_event: RawLogEvent { + signature, + logs, + has_error: false, + ingress: IngressMetadata { + source: IngressSource::KernelBypass, + hardware_timestamp_ns: None, + received_timestamp_ns: receive_timestamp_ns, + normalized_timestamp_ns, + }, + }, + dma_payload: payload, + }); + } + dataset +} + +fn synthetic_logs(index: usize) -> Vec { + let is_openbook = index.is_multiple_of(2); + if is_openbook { + vec![ + format!("Program {} invoke [1]", RAYDIUM_V4_PROGRAM_ID), + "Program log: initialize2".to_owned(), + ] + } else { + vec![ + format!("Program {} invoke [1]", RAYDIUM_STANDARD_AMM_PROGRAM_ID), + "Program log: vault_0_amount:1234, vault_1_amount:5678".to_owned(), + ] + } +} + +fn synthetic_dma_payload(signature: &str, logs: &[String]) -> Vec { + let mut payload = format!("signature={signature}\nhas_error=0\n"); + for log_line in logs { + payload.push_str("log="); + payload.push_str(log_line); + payload.push('\n'); + } + payload.into_bytes() +} + +fn benchmark_fpga_path(events: &[SyntheticEvent], burst_size: usize) -> ReplayPathStats { + let started_at = Instant::now(); + let mut candidate_count = 0_usize; + let mut per_event_ns = Vec::with_capacity(events.len()); + + for chunk in events.chunks(burst_size) { + for synthetic in chunk { + let event_start = Instant::now(); + if is_pool_creation_dma_payload(&synthetic.dma_payload) { + candidate_count = candidate_count.saturating_add(1); + } + per_event_ns.push(elapsed_ns_u64(event_start.elapsed())); + } + } + + build_replay_path_stats( + "fpga_dma", + events.len(), + candidate_count, + elapsed_ns_u64(started_at.elapsed()), + &per_event_ns, + ) +} + +fn benchmark_kernel_path(events: &[SyntheticEvent], burst_size: usize) -> ReplayPathStats { + let started_at = Instant::now(); + let mut candidate_count = 0_usize; + let mut per_event_ns = Vec::with_capacity(events.len()); + + for chunk in events.chunks(burst_size) { + for synthetic in chunk { + let event_start = Instant::now(); + if is_pool_creation_candidate_logs(&synthetic.kernel_event.logs) { + candidate_count = candidate_count.saturating_add(1); + } + per_event_ns.push(elapsed_ns_u64(event_start.elapsed())); + } + } + + build_replay_path_stats( + "kernel_bypass", + events.len(), + candidate_count, + elapsed_ns_u64(started_at.elapsed()), + &per_event_ns, + ) +} + +fn build_replay_path_stats( + path: &'static str, + total_events: usize, + candidate_events: usize, + elapsed_ns: u64, + per_event_ns: &[u64], +) -> ReplayPathStats { + let mut sorted = per_event_ns.to_vec(); + sorted.sort_unstable(); + + let p50_ns = percentile_bps(&sorted, 5_000); + let p99_ns = percentile_bps(&sorted, 9_900); + let max_ns = sorted.last().copied().unwrap_or(0); + let throughput_events_per_sec = throughput_per_second(total_events, elapsed_ns); + + ReplayPathStats { + path, + total_events, + candidate_events, + elapsed_ns, + throughput_events_per_sec, + p50_ns, + p99_ns, + max_ns, + } +} + +fn throughput_per_second(total_events: usize, elapsed_ns: u64) -> u64 { + if elapsed_ns == 0 { + return 0; + } + + let total_events_u64 = u64::try_from(total_events).unwrap_or(u64::MAX); + let numerator = u128::from(total_events_u64).saturating_mul(1_000_000_000_u128); + let value = numerator.checked_div(u128::from(elapsed_ns)).unwrap_or(0); + u64::try_from(value).unwrap_or(u64::MAX) +} + +fn percentile_bps(sorted: &[u64], bps: u16) -> u64 { + if sorted.is_empty() { + return 0; + } + + let max_index = sorted.len().saturating_sub(1); + let max_index_u64 = u64::try_from(max_index).unwrap_or(u64::MAX); + let numerator = u128::from(max_index_u64).saturating_mul(u128::from(bps)); + let index_u128 = numerator / 10_000_u128; + let index = usize::try_from(index_u128).unwrap_or(max_index); + sorted + .get(index) + .copied() + .or_else(|| sorted.get(max_index).copied()) + .unwrap_or(0) +} + +fn elapsed_ns_u64(duration: std::time::Duration) -> u64 { + u64::try_from(duration.as_nanos()).unwrap_or(u64::MAX) +} + +#[cfg(test)] +mod tests { + use super::run_synthetic_replay; + + #[test] + fn produces_non_empty_reports() { + let report = run_synthetic_replay(256, 32); + + assert_eq!(report.event_count, 256); + assert_eq!(report.burst_size, 32); + assert_eq!(report.fpga_path.total_events, 256); + assert_eq!(report.kernel_bypass_path.total_events, 256); + assert!(report.fpga_path.candidate_events > 0); + assert!(report.kernel_bypass_path.candidate_events > 0); + } +} diff --git a/src/slices/sniper/telemetry.rs b/src/slices/sniper/telemetry.rs new file mode 100644 index 0000000..7b0a5da --- /dev/null +++ b/src/slices/sniper/telemetry.rs @@ -0,0 +1,295 @@ +use std::sync::atomic::{AtomicU64, AtomicUsize, Ordering}; + +use tokio::time::{Duration, interval}; + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct HopLatencyStats { + pub sample_count: usize, + pub p50_ns: u64, + pub p99_ns: u64, + pub max_ns: u64, +} + +#[derive(Debug)] +struct AtomicSampleWindow { + hop: &'static str, + capacity: usize, + write_index: AtomicUsize, + sample_len: AtomicUsize, + samples: Box<[AtomicU64]>, +} + +impl AtomicSampleWindow { + fn new(hop: &'static str, capacity: usize) -> Self { + let mut samples = Vec::with_capacity(capacity); + for _ in 0..capacity { + samples.push(AtomicU64::new(0)); + } + + Self { + hop, + capacity, + write_index: AtomicUsize::new(0), + sample_len: AtomicUsize::new(0), + samples: samples.into_boxed_slice(), + } + } + + fn record(&self, duration_ns: u64) { + let write = self.write_index.fetch_add(1, Ordering::Relaxed); + let slot = modulo_index(write, self.capacity); + if let Some(sample) = self.samples.get(slot) { + sample.store(duration_ns, Ordering::Relaxed); + } + + let _update = self + .sample_len + .fetch_update(Ordering::Relaxed, Ordering::Relaxed, |value| { + if value < self.capacity { + Some(value.saturating_add(1)) + } else { + None + } + }); + } + + fn snapshot_stats(&self) -> Option<(&'static str, HopLatencyStats)> { + let len = self.sample_len.load(Ordering::Acquire).min(self.capacity); + if len == 0 { + return None; + } + + let write = self.write_index.load(Ordering::Acquire); + let start = write.saturating_sub(len); + + let mut values = Vec::with_capacity(len); + for offset in 0..len { + let index = modulo_index(start.saturating_add(offset), self.capacity); + let value = self + .samples + .get(index) + .map_or(0, |sample| sample.load(Ordering::Relaxed)); + values.push(value); + } + + Some((self.hop, stats_from_samples(&values))) + } +} + +#[derive(Debug)] +pub struct LatencyTelemetry { + enabled: bool, + slo_threshold_ns: u64, + ingress_to_engine: AtomicSampleWindow, + engine_classification: AtomicSampleWindow, + strategy_dispatch: AtomicSampleWindow, + dropped_unknown_hops: AtomicU64, +} + +impl LatencyTelemetry { + pub fn new(sample_capacity: usize, slo_threshold_ns: u64) -> Self { + Self::with_mode(true, sample_capacity, slo_threshold_ns) + } + + pub fn disabled() -> Self { + Self::with_mode(false, 1, 0) + } + + fn with_mode(enabled: bool, sample_capacity: usize, slo_threshold_ns: u64) -> Self { + let capacity = sample_capacity.max(1); + Self { + enabled, + slo_threshold_ns, + ingress_to_engine: AtomicSampleWindow::new("ingress_to_engine_ns", capacity), + engine_classification: AtomicSampleWindow::new("engine_classification_ns", capacity), + strategy_dispatch: AtomicSampleWindow::new("strategy_dispatch_ns", capacity), + dropped_unknown_hops: AtomicU64::new(0), + } + } + + pub const fn is_enabled(&self) -> bool { + self.enabled + } + + pub fn record(&self, hop: &'static str, duration_ns: u64) { + if !self.enabled { + return; + } + + match hop { + "ingress_to_engine_ns" => self.ingress_to_engine.record(duration_ns), + "engine_classification_ns" => self.engine_classification.record(duration_ns), + "strategy_dispatch_ns" => self.strategy_dispatch.record(duration_ns), + _ => { + self.dropped_unknown_hops.fetch_add(1, Ordering::Relaxed); + } + } + } + + pub fn snapshot_all(&self) -> Vec<(&'static str, HopLatencyStats)> { + if !self.enabled { + return Vec::new(); + } + + let mut stats = Vec::with_capacity(3); + + if let Some(value) = self.ingress_to_engine.snapshot_stats() { + stats.push(value); + } + if let Some(value) = self.engine_classification.snapshot_stats() { + stats.push(value); + } + if let Some(value) = self.strategy_dispatch.snapshot_stats() { + stats.push(value); + } + + stats.sort_by(|left, right| left.0.cmp(right.0)); + stats + } + + pub fn spawn_reporter(self: std::sync::Arc, period: Duration) { + if !self.enabled { + return; + } + + tokio::spawn(async move { + let mut ticker = interval(period); + loop { + ticker.tick().await; + self.emit_periodic_report(); + } + }); + } + + fn emit_periodic_report(&self) { + let stats = self.snapshot_all(); + for (hop, hop_stats) in stats { + log::info!( + "Latency telemetry > hop={} count={} p50={}ns p99={}ns max={}ns", + hop, + hop_stats.sample_count, + hop_stats.p50_ns, + hop_stats.p99_ns, + hop_stats.max_ns + ); + + if hop_stats.p99_ns > self.slo_threshold_ns || hop_stats.max_ns > self.slo_threshold_ns + { + log::warn!( + "Latency SLO alert > hop={} threshold={}ns p99={}ns max={}ns", + hop, + self.slo_threshold_ns, + hop_stats.p99_ns, + hop_stats.max_ns + ); + } + } + + let dropped_unknown_hops = self.dropped_unknown_hops.load(Ordering::Relaxed); + if dropped_unknown_hops > 0 { + log::warn!( + "Latency telemetry > dropped unsupported hop samples={}", + dropped_unknown_hops + ); + } + } +} + +fn modulo_index(value: usize, modulus: usize) -> usize { + value.checked_rem(modulus).unwrap_or(0) +} + +fn stats_from_samples(samples: &[u64]) -> HopLatencyStats { + if samples.is_empty() { + return HopLatencyStats { + sample_count: 0, + p50_ns: 0, + p99_ns: 0, + max_ns: 0, + }; + } + + let mut sorted = samples.to_vec(); + sorted.sort_unstable(); + + let p50_ns = percentile_bps(&sorted, 5_000); + let p99_ns = percentile_bps(&sorted, 9_900); + let max_ns = sorted.last().copied().unwrap_or(0); + + HopLatencyStats { + sample_count: sorted.len(), + p50_ns, + p99_ns, + max_ns, + } +} + +fn percentile_bps(sorted_samples: &[u64], bps: u16) -> u64 { + if sorted_samples.is_empty() { + return 0; + } + + let max_index = sorted_samples.len().saturating_sub(1); + let max_index_u64 = u64::try_from(max_index).unwrap_or(u64::MAX); + let numerator = u128::from(max_index_u64).saturating_mul(u128::from(bps)); + let index_u128 = numerator / 10_000_u128; + let index = usize::try_from(index_u128).unwrap_or(max_index); + + sorted_samples + .get(index) + .copied() + .or_else(|| sorted_samples.get(max_index).copied()) + .unwrap_or(0) +} + +#[cfg(test)] +mod tests { + use super::LatencyTelemetry; + + #[test] + fn computes_p50_p99_and_max() { + let telemetry = LatencyTelemetry::new(64, 1_000_000); + for value in [10_u64, 20, 30, 40, 50, 60, 70, 80, 90, 100] { + telemetry.record("ingress_to_engine_ns", value); + } + + let snapshots = telemetry.snapshot_all(); + assert_eq!(snapshots.len(), 1); + assert!(!snapshots.is_empty()); + + if let Some((_, stats)) = snapshots.first().copied() { + assert_eq!(stats.sample_count, 10); + assert_eq!(stats.p50_ns, 50); + assert_eq!(stats.p99_ns, 90); + assert_eq!(stats.max_ns, 100); + } + } + + #[test] + fn keeps_only_recent_samples_per_hop() { + let telemetry = LatencyTelemetry::new(3, 1_000_000); + telemetry.record("ingress_to_engine_ns", 1); + telemetry.record("ingress_to_engine_ns", 2); + telemetry.record("ingress_to_engine_ns", 3); + telemetry.record("ingress_to_engine_ns", 4); + + let snapshots = telemetry.snapshot_all(); + assert_eq!(snapshots.len(), 1); + assert!(!snapshots.is_empty()); + if let Some((_, stats)) = snapshots.first().copied() { + assert_eq!(stats.sample_count, 3); + assert_eq!(stats.max_ns, 4); + } + } + + #[test] + fn disabled_telemetry_is_noop() { + let telemetry = LatencyTelemetry::disabled(); + telemetry.record("ingress_to_engine_ns", 1_000); + telemetry.record("engine_classification_ns", 2_000); + + let snapshots = telemetry.snapshot_all(); + assert!(snapshots.is_empty()); + assert!(!telemetry.is_enabled()); + } +} diff --git a/src/utils.rs b/src/utils.rs deleted file mode 100644 index af3d0c9..0000000 --- a/src/utils.rs +++ /dev/null @@ -1,115 +0,0 @@ -use std::{collections::HashMap, str::FromStr}; - -use regex::Regex; -use solana_sdk::pubkey::Pubkey; -use tokio::{fs::File, io::{AsyncBufReadExt, BufReader}}; - -pub fn get_data_from_logs_by_regex(logs: &Vec, regex: &str) -> Option { - let regex = Regex::new(regex).unwrap(); - - let mut data: Option = None; - - for log in logs { - if let Some(captures) = regex.captures(log) { - if let Some(str) = captures.get(1) { - data = Some(str.as_str().to_string()); - break; - } - } - } - - data -} - -pub async fn read_mints_or_deployers_from_file(filename: &str, file_type: &str, initial: bool) -> Result, std::io::Error> { - let file = File::open(filename).await?; - let reader = BufReader::new(file); - let mut lines = reader.lines(); - let mut data = Vec::new(); - - while let Some(line) = lines.next_line().await? { - if line.is_empty() || line.starts_with('#') { - continue; - } - - let parts: Vec<&str> = line.split('|').collect(); - if parts.len() == 4 { - let address = parts[0].to_owned(); - let snipe_height = parts[1].parse::().expect(&format!("{} > Invalid snipe height on address {}", file_type, address)); - let jito_tip = parts[2].parse::().expect(&format!("{} > Invalid jito tip on address {}", file_type, address)); - let slippage = parts[3].parse::().expect(&format!("{} > Invalid slippage on address {}", file_type, address)); - - if Pubkey::from_str(&address).is_err() { - log_with_panic(format!("{} > Invalid address {}", file_type, address), initial); - } - - if snipe_height <= 0.0 { - log_with_panic(format!("{} > Invalid snipe height {}. Snipe height must be greater than 0 on address {}", file_type, snipe_height, address), initial); - } - - if jito_tip <= 0.0 { - log_with_panic(format!("{} > Invalid jito tip {}. Jito tip must be greater than 0 on address {}", file_type, jito_tip, address), initial); - } - - if slippage < 0.0 || slippage > 100.0 { - log_with_panic(format!("{} > Invalid slippage {}. Slippage must be between 0 and 100 on address {}", file_type, slippage, address), initial); - } - - data.push((address, snipe_height, jito_tip, slippage)); - } else { - log_with_panic(format!("Each {} element must be formatted as 'address|snipe height|jito tip|slippage' for line '{}'", file_type, line), initial); - } - } - - for (address, _snipe_height, _jito_tip, _slippage) in &data { - if data.iter().filter(|(a, _snipe_height, _jito_tip, _slippage)| a == address).count() > 1 { - log_with_panic(format!("{} > Same address used multiple times {}", file_type, address), initial); - } - } - - Ok(data) -} - -pub fn report_changes(old_data: &[(String, f64, f64, f64)], new_data: &[(String, f64, f64, f64)], config_name: &str, initial: bool) { - if initial { - return; - } - - let old_map: HashMap = old_data.iter().map(|x| (x.0.clone(), (x.1, x.2, x.3))).collect(); - let new_map: HashMap = new_data.iter().map(|x| (x.0.clone(), (x.1, x.2, x.3))).collect(); - - for (new_key, new_value) in &new_map { - match old_map.get(new_key) { - Some(old_value) if old_value != new_value => { - let (old_snipe_height, old_jito_tip, old_slippage) = old_value; - let (new_snipe_height, new_jito_tip, new_slippage) = new_value; - - log::info!("{} > Updated - {} \n\t\tOld > Snipe height: {} SOL, Jito tip: {} SOL, Slippage: {} % \n\t\tNew > Snipe height: {} SOL, Jito tip: {} SOL, Slippage: {} %", config_name, new_key, old_snipe_height, old_jito_tip, old_slippage, new_snipe_height, new_jito_tip, new_slippage); - }, - None => { - let (new_snipe_height, new_jito_tip, new_slippage) = new_value; - - log::info!("{} > Added - {} \n\t\tValue > Snipe height: {} SOL, Jito tip: {} SOL, Slippage: {} %", config_name, new_key, new_snipe_height, new_jito_tip, new_slippage); - }, - _ => {} - } - } - - for old_key in old_map.keys() { - if !new_map.contains_key(old_key) { - log::info!("{} > Removed - {}", config_name, old_key); - } - } - - if old_map == new_map { - log::info!("{}: No changes detected.", config_name); - } -} - -pub fn log_with_panic(message: String, initial: bool) { - log::error!("{}", message); - - if initial { - std::process::exit(1); - } -} diff --git a/tests/e2e_ingress_stack.rs b/tests/e2e_ingress_stack.rs new file mode 100644 index 0000000..a04b123 --- /dev/null +++ b/tests/e2e_ingress_stack.rs @@ -0,0 +1,125 @@ +use std::{sync::Arc, time::Duration}; + +use sniper::{ + adapters::{fpga_feed::FpgaFeedAdapter, raydium::RAYDIUM_V4_PROGRAM_ID}, + app::context::ExecutionContext, + domain::{ + aggregates::RuleBook, + events::{IngressMetadata, IngressSource, RawLogEvent, unix_timestamp_now_ns}, + value_objects::TxSubmissionMode, + }, + ports::fpga_feed::FpgaFeedPort, + slices::sniper::{engine::SniperEngine, telemetry::LatencyTelemetry}, +}; +use solana_client::nonblocking::rpc_client::RpcClient; +use solana_sdk::signature::{Keypair, Signature}; +use tokio::sync::{mpsc, watch}; + +#[tokio::test] +async fn e2e_kernel_bypass_software_stack_records_latency() { + let (events_tx, events_rx) = mpsc::unbounded_channel(); + let (rulebook_tx, rulebook_rx) = watch::channel(Arc::new(RuleBook::default())); + let telemetry = Arc::new(LatencyTelemetry::new(128, 1_000_000_000)); + + let engine = SniperEngine::new( + test_context(), + events_rx, + rulebook_rx, + Arc::clone(&telemetry), + ); + let engine_task = tokio::spawn(async move { + engine.run().await; + }); + + let send_result = events_tx.send(RawLogEvent { + signature: Signature::new_unique().to_string(), + logs: vec!["Program log: not_a_pool_creation_event".to_owned()], + has_error: false, + ingress: IngressMetadata::from_receive_clock( + IngressSource::KernelBypass, + unix_timestamp_now_ns(), + ), + }); + assert!(send_result.is_ok()); + + drop(events_tx); + drop(rulebook_tx); + + assert!(wait_for_hop_samples(&telemetry, "engine_classification_ns", 1).await); + assert!(wait_for_hop_samples(&telemetry, "ingress_to_engine_ns", 1).await); + + let joined = tokio::time::timeout(Duration::from_secs(1), engine_task).await; + assert!(joined.is_ok()); + if let Ok(joined) = joined { + assert!(joined.is_ok()); + } +} + +#[tokio::test] +async fn e2e_fpga_dma_stack_records_latency_without_network_calls() { + let (events_tx, events_rx) = mpsc::unbounded_channel(); + let (rulebook_tx, rulebook_rx) = watch::channel(Arc::new(RuleBook::default())); + let telemetry = Arc::new(LatencyTelemetry::new(128, 1_000_000_000)); + + let engine = SniperEngine::new( + test_context(), + events_rx, + rulebook_rx, + Arc::clone(&telemetry), + ); + let engine_task = tokio::spawn(async move { + engine.run().await; + }); + + let payload = format!( + "signature=not_base58_signature!\nhas_error=0\nlog=Program {}\nlog=Program log: initialize2", + RAYDIUM_V4_PROGRAM_ID + ); + let adapter = + FpgaFeedAdapter::with_mock_dma_payload("mock_dma".to_owned(), true, payload.as_bytes()); + + let spawned = adapter.spawn_stream(events_tx.clone()); + assert!(spawned.is_ok()); + + drop(events_tx); + drop(rulebook_tx); + + assert!(wait_for_hop_samples(&telemetry, "engine_classification_ns", 1).await); + assert!(wait_for_hop_samples(&telemetry, "ingress_to_engine_ns", 1).await); + + let joined = tokio::time::timeout(Duration::from_secs(1), engine_task).await; + assert!(joined.is_ok()); + if let Ok(joined) = joined { + assert!(joined.is_ok()); + } +} + +async fn wait_for_hop_samples( + telemetry: &LatencyTelemetry, + hop: &'static str, + minimum_samples: usize, +) -> bool { + for _ in 0..25 { + let matched = telemetry + .snapshot_all() + .into_iter() + .any(|(name, stats)| name == hop && stats.sample_count >= minimum_samples); + if matched { + return true; + } + + tokio::time::sleep(Duration::from_millis(20)).await; + } + + false +} + +fn test_context() -> Arc { + Arc::new(ExecutionContext { + priority_fees: 1, + rpc: Arc::new(RpcClient::new("http://127.0.0.1:8899".to_owned())), + keypair: Arc::new(Keypair::new()), + tx_submission_mode: TxSubmissionMode::Direct, + jito_url: Arc::new("http://127.0.0.1:8899".to_owned()), + }) +}