From 4aa77ee28a695e9fe062ab90552ccf4f8a2ea3a0 Mon Sep 17 00:00:00 2001 From: jasl Date: Wed, 12 Mar 2025 12:33:13 +0800 Subject: [PATCH] Add DePHY vending machine example --- .../dephy-vending-machine-examples.dockerfile | 14 + .../.github/workflows/build_then_release.yml | 170 + .../.github/workflows/check_and_test.yml | 40 + dephy-vending_machine-examples/.gitignore | 13 + .../.pre-commit-config.yaml | 54 + .../.prettierignore | 9 + dephy-vending_machine-examples/Cargo.lock | 7413 +++++++++++++++++ dephy-vending_machine-examples/Cargo.toml | 36 + dephy-vending_machine-examples/MIT-LICENSE | 20 + dephy-vending_machine-examples/README.md | 42 + .../balance-payment-sdk/Cargo.lock | 5616 +++++++++++++ .../balance-payment-sdk/Cargo.toml | 26 + .../balance-payment-sdk/src/error.rs | 16 + .../src/generated/accounts/global_account.rs | 77 + .../src/generated/accounts/lock_account.rs | 62 + .../src/generated/accounts/mod.rs | 14 + .../src/generated/accounts/user_account.rs | 69 + .../src/generated/errors/balance_payment.rs | 43 + .../src/generated/errors/mod.rs | 10 + .../src/generated/instructions/deposit.rs | 472 ++ .../src/generated/instructions/initialize.rs | 475 ++ .../src/generated/instructions/lock.rs | 606 ++ .../src/generated/instructions/mod.rs | 26 + .../src/generated/instructions/pay.rs | 610 ++ .../src/generated/instructions/register.rs | 434 + .../src/generated/instructions/set_bot.rs | 395 + .../generated/instructions/set_treasury.rs | 399 + .../src/generated/instructions/settle.rs | 645 ++ .../src/generated/instructions/withdraw.rs | 472 ++ .../balance-payment-sdk/src/generated/mod.rs | 14 + .../src/generated/programs.rs | 11 + .../generated/types/e_d25519_recover_info.rs | 19 + .../src/generated/types/mod.rs | 10 + .../balance-payment-sdk/src/lib.rs | 293 + .../balance-payment-sdk/src/verify.rs | 61 + .../balance-payment/Anchor.toml | 19 + .../balance-payment/Cargo.lock | 2126 +++++ .../balance-payment/Cargo.toml | 13 + .../balance-payment/README.md | 96 + .../balance-payment/app/.env.example | 2 + .../balance-payment/app/.gitignore | 25 + .../balance-payment/app/.prettierignore | 8 + .../balance-payment/app/.prettierrc | 7 + .../balance-payment/app/LICENSE | 21 + .../balance-payment/app/README.md | 7 + .../balance-payment/app/eslint.config.js | 25 + .../balance-payment/app/index.html | 13 + .../balance-payment/app/package.json | 58 + .../balance-payment/app/postcss.config.mjs | 8 + .../balance-payment/app/public/logo.png | Bin 0 -> 12306 bytes .../app/src/anchor/balance_payment.json | 818 ++ .../app/src/anchor/balance_payment.ts | 824 ++ .../balance-payment/app/src/anchor/index.ts | 29 + .../app/src/app/app-routes.tsx | 32 + .../balance-payment/app/src/app/app.tsx | 18 + .../balance-payment/app/src/app/favicon.ico | Bin 0 -> 32038 bytes .../balance-payment/app/src/assets/react.svg | 1 + .../account/account-data-access.tsx | 174 + .../account/account-detail-feature.tsx | 44 + .../account/account-list-feature.tsx | 19 + .../app/src/components/account/account-ui.tsx | 347 + .../balance-payment-data-access.tsx | 72 + .../balance-payment-feature.tsx | 721 ++ .../cluster/cluster-data-access.tsx | 118 + .../components/cluster/cluster-feature.tsx | 19 + .../app/src/components/cluster/cluster-ui.tsx | 172 + .../dashboard/dashboard-feature.tsx | 29 + .../src/components/solana/solana-provider.tsx | 39 + .../app/src/components/ui/ui-layout.tsx | 156 + .../balance-payment/app/src/index.css | 20 + .../balance-payment/app/src/main.tsx | 13 + .../balance-payment/app/src/vite-env.d.ts | 1 + .../balance-payment/app/tailwind.config.ts | 14 + .../balance-payment/app/tsconfig.app.json | 28 + .../balance-payment/app/tsconfig.json | 4 + .../balance-payment/app/tsconfig.node.json | 25 + .../balance-payment/app/vite.config.ts | 34 + .../bot_example_js/.dockerignore | 11 + .../balance-payment/bot_example_js/Dockerfile | 14 + .../balance-payment/bot_example_js/README.md | 36 + .../bot_example_js/balance_payment.json | 932 +++ .../bot_example_js/balance_payment.ts | 938 +++ .../bot_example_js/bin/eligible-checker | 8 + .../balance-payment/bot_example_js/bin/locker | 7 + .../bot_example_js/bin/settler | 7 + .../balance-payment/bot_example_js/index.ts | 618 ++ .../bot_example_js/package.json | 27 + .../bot_example_js/tsconfig.json | 11 + .../balance-payment/migrations/deploy.ts | 12 + .../balance-payment/package.json | 30 + .../programs/balance-payment/Cargo.toml | 26 + .../programs/balance-payment/Xargo.toml | 2 + .../programs/balance-payment/keypair.json | 1 + .../programs/balance-payment/src/constants.rs | 2 + .../programs/balance-payment/src/errors.rs | 17 + .../src/instructions/deposit.rs | 33 + .../src/instructions/initialize.rs | 29 + .../balance-payment/src/instructions/lock.rs | 98 + .../balance-payment/src/instructions/mod.rs | 19 + .../balance-payment/src/instructions/pay.rs | 63 + .../src/instructions/register.rs | 24 + .../src/instructions/set_bot.rs | 21 + .../src/instructions/set_treasury.rs | 21 + .../src/instructions/settle.rs | 75 + .../src/instructions/withdraw.rs | 40 + .../programs/balance-payment/src/lib.rs | 52 + .../balance-payment/src/state/global.rs | 9 + .../balance-payment/src/state/lock.rs | 7 + .../programs/balance-payment/src/state/mod.rs | 7 + .../balance-payment/src/state/user.rs | 9 + .../balance-payment/src/utils/ed25519.rs | 51 + .../programs/balance-payment/src/utils/mod.rs | 3 + .../balance-payment/scripts/cli.ts | 354 + .../balance-payment/tests/balance-payment.ts | 341 + .../balance-payment/tsconfig.json | 11 + dephy-vending_machine-examples/cliff.toml | 95 + dephy-vending_machine-examples/deny.toml | 58 + .../doc/architecture.png | Bin 0 -> 274452 bytes .../migrate.sh | 17 + .../20241125030333_initial.sql | 16 + .../docker-compose.yml | 85 + .../examples/decharge-controller/Cargo.toml | 29 + .../examples/decharge-controller/README.md | 84 + .../bin/dephy-decharge-controller-node.rs | 128 + .../bin/dephy-decharge-controller-server.rs | 110 + .../decharge-controller/examples/cli.rs | 158 + .../migrations/20250116011256_initial.sql | 6 + .../examples/decharge-controller/src/lib.rs | 9 + .../decharge-controller/src/message.rs | 50 + .../src/node/message_handler.rs | 390 + .../decharge-controller/src/node/mod.rs | 3 + .../decharge-controller/src/relay_client.rs | 182 + .../src/server/message_handler.rs | 254 + .../decharge-controller/src/server/mod.rs | 5 + .../decharge-controller/src/server/state.rs | 123 + .../examples/gacha-controller/Cargo.toml | 18 + .../examples/gacha-controller/README.md | 52 + .../examples/gacha-controller/examples/cli.rs | 158 + .../examples/gacha-controller/src/lib.rs | 8 + .../examples/gacha-controller/src/main.rs | 147 + .../examples/gacha-controller/src/message.rs | 50 + .../src/node/message_handler.rs | 378 + .../examples/gacha-controller/src/node/mod.rs | 3 + .../gacha-controller/src/relay_client.rs | 182 + .../keypairs/bot.demo.json | 1 + .../keypairs/user.demo.json | 1 + dephy-vending_machine-examples/rustfmt.toml | 13 + dephy-vending_machine-examples/taplo.toml | 36 + dephy-vending_machine-examples/typos.toml | 3 + 149 files changed, 31703 insertions(+) create mode 100644 dephy-vending_machine-examples/.github/dockerfiles/dephy-vending-machine-examples.dockerfile create mode 100644 dephy-vending_machine-examples/.github/workflows/build_then_release.yml create mode 100644 dephy-vending_machine-examples/.github/workflows/check_and_test.yml create mode 100644 dephy-vending_machine-examples/.gitignore create mode 100644 dephy-vending_machine-examples/.pre-commit-config.yaml create mode 100644 dephy-vending_machine-examples/.prettierignore create mode 100644 dephy-vending_machine-examples/Cargo.lock create mode 100644 dephy-vending_machine-examples/Cargo.toml create mode 100644 dephy-vending_machine-examples/MIT-LICENSE create mode 100644 dephy-vending_machine-examples/README.md create mode 100644 dephy-vending_machine-examples/balance-payment-sdk/Cargo.lock create mode 100644 dephy-vending_machine-examples/balance-payment-sdk/Cargo.toml create mode 100644 dephy-vending_machine-examples/balance-payment-sdk/src/error.rs create mode 100644 dephy-vending_machine-examples/balance-payment-sdk/src/generated/accounts/global_account.rs create mode 100644 dephy-vending_machine-examples/balance-payment-sdk/src/generated/accounts/lock_account.rs create mode 100644 dephy-vending_machine-examples/balance-payment-sdk/src/generated/accounts/mod.rs create mode 100644 dephy-vending_machine-examples/balance-payment-sdk/src/generated/accounts/user_account.rs create mode 100644 dephy-vending_machine-examples/balance-payment-sdk/src/generated/errors/balance_payment.rs create mode 100644 dephy-vending_machine-examples/balance-payment-sdk/src/generated/errors/mod.rs create mode 100644 dephy-vending_machine-examples/balance-payment-sdk/src/generated/instructions/deposit.rs create mode 100644 dephy-vending_machine-examples/balance-payment-sdk/src/generated/instructions/initialize.rs create mode 100644 dephy-vending_machine-examples/balance-payment-sdk/src/generated/instructions/lock.rs create mode 100644 dephy-vending_machine-examples/balance-payment-sdk/src/generated/instructions/mod.rs create mode 100644 dephy-vending_machine-examples/balance-payment-sdk/src/generated/instructions/pay.rs create mode 100644 dephy-vending_machine-examples/balance-payment-sdk/src/generated/instructions/register.rs create mode 100644 dephy-vending_machine-examples/balance-payment-sdk/src/generated/instructions/set_bot.rs create mode 100644 dephy-vending_machine-examples/balance-payment-sdk/src/generated/instructions/set_treasury.rs create mode 100644 dephy-vending_machine-examples/balance-payment-sdk/src/generated/instructions/settle.rs create mode 100644 dephy-vending_machine-examples/balance-payment-sdk/src/generated/instructions/withdraw.rs create mode 100644 dephy-vending_machine-examples/balance-payment-sdk/src/generated/mod.rs create mode 100644 dephy-vending_machine-examples/balance-payment-sdk/src/generated/programs.rs create mode 100644 dephy-vending_machine-examples/balance-payment-sdk/src/generated/types/e_d25519_recover_info.rs create mode 100644 dephy-vending_machine-examples/balance-payment-sdk/src/generated/types/mod.rs create mode 100644 dephy-vending_machine-examples/balance-payment-sdk/src/lib.rs create mode 100644 dephy-vending_machine-examples/balance-payment-sdk/src/verify.rs create mode 100644 dephy-vending_machine-examples/balance-payment/Anchor.toml create mode 100644 dephy-vending_machine-examples/balance-payment/Cargo.lock create mode 100644 dephy-vending_machine-examples/balance-payment/Cargo.toml create mode 100644 dephy-vending_machine-examples/balance-payment/README.md create mode 100644 dephy-vending_machine-examples/balance-payment/app/.env.example create mode 100644 dephy-vending_machine-examples/balance-payment/app/.gitignore create mode 100644 dephy-vending_machine-examples/balance-payment/app/.prettierignore create mode 100644 dephy-vending_machine-examples/balance-payment/app/.prettierrc create mode 100644 dephy-vending_machine-examples/balance-payment/app/LICENSE create mode 100644 dephy-vending_machine-examples/balance-payment/app/README.md create mode 100644 dephy-vending_machine-examples/balance-payment/app/eslint.config.js create mode 100644 dephy-vending_machine-examples/balance-payment/app/index.html create mode 100644 dephy-vending_machine-examples/balance-payment/app/package.json create mode 100644 dephy-vending_machine-examples/balance-payment/app/postcss.config.mjs create mode 100644 dephy-vending_machine-examples/balance-payment/app/public/logo.png create mode 100644 dephy-vending_machine-examples/balance-payment/app/src/anchor/balance_payment.json create mode 100644 dephy-vending_machine-examples/balance-payment/app/src/anchor/balance_payment.ts create mode 100644 dephy-vending_machine-examples/balance-payment/app/src/anchor/index.ts create mode 100644 dephy-vending_machine-examples/balance-payment/app/src/app/app-routes.tsx create mode 100644 dephy-vending_machine-examples/balance-payment/app/src/app/app.tsx create mode 100644 dephy-vending_machine-examples/balance-payment/app/src/app/favicon.ico create mode 100644 dephy-vending_machine-examples/balance-payment/app/src/assets/react.svg create mode 100644 dephy-vending_machine-examples/balance-payment/app/src/components/account/account-data-access.tsx create mode 100644 dephy-vending_machine-examples/balance-payment/app/src/components/account/account-detail-feature.tsx create mode 100644 dephy-vending_machine-examples/balance-payment/app/src/components/account/account-list-feature.tsx create mode 100644 dephy-vending_machine-examples/balance-payment/app/src/components/account/account-ui.tsx create mode 100644 dephy-vending_machine-examples/balance-payment/app/src/components/balance-payment/balance-payment-data-access.tsx create mode 100644 dephy-vending_machine-examples/balance-payment/app/src/components/balance-payment/balance-payment-feature.tsx create mode 100644 dephy-vending_machine-examples/balance-payment/app/src/components/cluster/cluster-data-access.tsx create mode 100644 dephy-vending_machine-examples/balance-payment/app/src/components/cluster/cluster-feature.tsx create mode 100644 dephy-vending_machine-examples/balance-payment/app/src/components/cluster/cluster-ui.tsx create mode 100644 dephy-vending_machine-examples/balance-payment/app/src/components/dashboard/dashboard-feature.tsx create mode 100644 dephy-vending_machine-examples/balance-payment/app/src/components/solana/solana-provider.tsx create mode 100644 dephy-vending_machine-examples/balance-payment/app/src/components/ui/ui-layout.tsx create mode 100644 dephy-vending_machine-examples/balance-payment/app/src/index.css create mode 100644 dephy-vending_machine-examples/balance-payment/app/src/main.tsx create mode 100644 dephy-vending_machine-examples/balance-payment/app/src/vite-env.d.ts create mode 100644 dephy-vending_machine-examples/balance-payment/app/tailwind.config.ts create mode 100644 dephy-vending_machine-examples/balance-payment/app/tsconfig.app.json create mode 100644 dephy-vending_machine-examples/balance-payment/app/tsconfig.json create mode 100644 dephy-vending_machine-examples/balance-payment/app/tsconfig.node.json create mode 100644 dephy-vending_machine-examples/balance-payment/app/vite.config.ts create mode 100644 dephy-vending_machine-examples/balance-payment/bot_example_js/.dockerignore create mode 100644 dephy-vending_machine-examples/balance-payment/bot_example_js/Dockerfile create mode 100644 dephy-vending_machine-examples/balance-payment/bot_example_js/README.md create mode 100644 dephy-vending_machine-examples/balance-payment/bot_example_js/balance_payment.json create mode 100644 dephy-vending_machine-examples/balance-payment/bot_example_js/balance_payment.ts create mode 100755 dephy-vending_machine-examples/balance-payment/bot_example_js/bin/eligible-checker create mode 100755 dephy-vending_machine-examples/balance-payment/bot_example_js/bin/locker create mode 100755 dephy-vending_machine-examples/balance-payment/bot_example_js/bin/settler create mode 100644 dephy-vending_machine-examples/balance-payment/bot_example_js/index.ts create mode 100644 dephy-vending_machine-examples/balance-payment/bot_example_js/package.json create mode 100644 dephy-vending_machine-examples/balance-payment/bot_example_js/tsconfig.json create mode 100644 dephy-vending_machine-examples/balance-payment/migrations/deploy.ts create mode 100644 dephy-vending_machine-examples/balance-payment/package.json create mode 100644 dephy-vending_machine-examples/balance-payment/programs/balance-payment/Cargo.toml create mode 100644 dephy-vending_machine-examples/balance-payment/programs/balance-payment/Xargo.toml create mode 100644 dephy-vending_machine-examples/balance-payment/programs/balance-payment/keypair.json create mode 100644 dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/constants.rs create mode 100644 dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/errors.rs create mode 100644 dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/instructions/deposit.rs create mode 100644 dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/instructions/initialize.rs create mode 100644 dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/instructions/lock.rs create mode 100644 dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/instructions/mod.rs create mode 100644 dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/instructions/pay.rs create mode 100644 dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/instructions/register.rs create mode 100644 dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/instructions/set_bot.rs create mode 100644 dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/instructions/set_treasury.rs create mode 100644 dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/instructions/settle.rs create mode 100644 dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/instructions/withdraw.rs create mode 100644 dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/lib.rs create mode 100644 dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/state/global.rs create mode 100644 dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/state/lock.rs create mode 100644 dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/state/mod.rs create mode 100644 dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/state/user.rs create mode 100644 dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/utils/ed25519.rs create mode 100644 dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/utils/mod.rs create mode 100644 dephy-vending_machine-examples/balance-payment/scripts/cli.ts create mode 100644 dephy-vending_machine-examples/balance-payment/tests/balance-payment.ts create mode 100644 dephy-vending_machine-examples/balance-payment/tsconfig.json create mode 100644 dephy-vending_machine-examples/cliff.toml create mode 100644 dephy-vending_machine-examples/deny.toml create mode 100644 dephy-vending_machine-examples/doc/architecture.png create mode 100755 dephy-vending_machine-examples/docker-compose-postgres-init/decharge-controller-docker-entrypoint-initdb.d/migrate.sh create mode 100644 dephy-vending_machine-examples/docker-compose-postgres-init/messaging_network_migrations/20241125030333_initial.sql create mode 100644 dephy-vending_machine-examples/docker-compose.yml create mode 100644 dephy-vending_machine-examples/examples/decharge-controller/Cargo.toml create mode 100644 dephy-vending_machine-examples/examples/decharge-controller/README.md create mode 100644 dephy-vending_machine-examples/examples/decharge-controller/bin/dephy-decharge-controller-node.rs create mode 100644 dephy-vending_machine-examples/examples/decharge-controller/bin/dephy-decharge-controller-server.rs create mode 100644 dephy-vending_machine-examples/examples/decharge-controller/examples/cli.rs create mode 100644 dephy-vending_machine-examples/examples/decharge-controller/migrations/20250116011256_initial.sql create mode 100644 dephy-vending_machine-examples/examples/decharge-controller/src/lib.rs create mode 100644 dephy-vending_machine-examples/examples/decharge-controller/src/message.rs create mode 100644 dephy-vending_machine-examples/examples/decharge-controller/src/node/message_handler.rs create mode 100644 dephy-vending_machine-examples/examples/decharge-controller/src/node/mod.rs create mode 100644 dephy-vending_machine-examples/examples/decharge-controller/src/relay_client.rs create mode 100644 dephy-vending_machine-examples/examples/decharge-controller/src/server/message_handler.rs create mode 100644 dephy-vending_machine-examples/examples/decharge-controller/src/server/mod.rs create mode 100644 dephy-vending_machine-examples/examples/decharge-controller/src/server/state.rs create mode 100644 dephy-vending_machine-examples/examples/gacha-controller/Cargo.toml create mode 100644 dephy-vending_machine-examples/examples/gacha-controller/README.md create mode 100644 dephy-vending_machine-examples/examples/gacha-controller/examples/cli.rs create mode 100644 dephy-vending_machine-examples/examples/gacha-controller/src/lib.rs create mode 100644 dephy-vending_machine-examples/examples/gacha-controller/src/main.rs create mode 100644 dephy-vending_machine-examples/examples/gacha-controller/src/message.rs create mode 100644 dephy-vending_machine-examples/examples/gacha-controller/src/node/message_handler.rs create mode 100644 dephy-vending_machine-examples/examples/gacha-controller/src/node/mod.rs create mode 100644 dephy-vending_machine-examples/examples/gacha-controller/src/relay_client.rs create mode 100644 dephy-vending_machine-examples/keypairs/bot.demo.json create mode 100644 dephy-vending_machine-examples/keypairs/user.demo.json create mode 100644 dephy-vending_machine-examples/rustfmt.toml create mode 100644 dephy-vending_machine-examples/taplo.toml create mode 100644 dephy-vending_machine-examples/typos.toml diff --git a/dephy-vending_machine-examples/.github/dockerfiles/dephy-vending-machine-examples.dockerfile b/dephy-vending_machine-examples/.github/dockerfiles/dephy-vending-machine-examples.dockerfile new file mode 100644 index 0000000..6481442 --- /dev/null +++ b/dephy-vending_machine-examples/.github/dockerfiles/dephy-vending-machine-examples.dockerfile @@ -0,0 +1,14 @@ +FROM alpine:3.21 + +ARG TARGETPLATFORM + +ENV RUST_LOG=info + +WORKDIR /opt/dephy-vending-machine-examples +RUN adduser -D dephy --uid 1573 && chown -R dephy:dephy /opt/dephy-vending-machine-examples + +COPY ./${TARGETPLATFORM}/dephy-decharge-controller-server /usr/bin/dephy-decharge-controller-server +COPY ./${TARGETPLATFORM}/dephy-decharge-controller-node /usr/bin/dephy-decharge-controller-node +COPY ./${TARGETPLATFORM}/dephy-gacha-controller /usr/bin/dephy-gacha-controller + +USER dephy diff --git a/dephy-vending_machine-examples/.github/workflows/build_then_release.yml b/dephy-vending_machine-examples/.github/workflows/build_then_release.yml new file mode 100644 index 0000000..c3daf76 --- /dev/null +++ b/dephy-vending_machine-examples/.github/workflows/build_then_release.yml @@ -0,0 +1,170 @@ +name: Build then release + +on: + push: + tags: + - "v*" + branches: + - "main" + +env: + CARGO_TERM_COLOR: always + +jobs: + gen_version: + name: Generate version + runs-on: ubuntu-latest + outputs: + version: ${{ steps.generated-tag.outputs.tag }} + steps: + - uses: actions/checkout@v4 + - name: Get latest tag + id: get-latest-tag + run: | + echo "tag=`gh release list -L 1 | cut -f 1`" >> $GITHUB_OUTPUT + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Bump version + id: generated-tag + uses: actions/github-script@v6 + with: + script: | + if (context.ref.startsWith("refs/tags/")) { + let tag = context.ref.replace("refs/tags/", ""); + core.setOutput('tag', tag); + console.log(`This event pushed a tag ${tag}, return directly.`) + return + } + console.log('Use default tag "prerelease".') + core.setOutput('tag', 'prerelease'); + + build: + needs: gen_version + name: Build + runs-on: ${{ matrix.runner }} + strategy: + matrix: + include: + - target: x86_64-apple-darwin + runner: macos-latest + build_env: {} + - target: aarch64-apple-darwin + runner: macos-latest + build_env: {} + - target: x86_64-unknown-linux-musl + runner: ubuntu-latest + build_env: {} + - target: aarch64-unknown-linux-musl + runner: ubuntu-latest + build_env: + CARGO_TARGET_AARCH64_UNKNOWN_LINUX_MUSL_RUSTFLAGS: "-Clink-self-contained=yes -Clinker=rust-lld" + CC_aarch64_unknown_linux_musl: clang + AR_aarch64_unknown_linux_musl: llvm-ar + + steps: + - uses: actions/checkout@v4 + - name: Setup protoc + uses: arduino/setup-protoc@v3.0.0 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + - name: Install musl-tools + if: matrix.runner == 'ubuntu-latest' + run: sudo apt update && sudo apt install -y musl-tools + - name: Install cross build deps for aarch64-unknown-linux-musl + if: matrix.target == 'aarch64-unknown-linux-musl' + run: sudo apt update && sudo apt install -y clang llvm gcc-aarch64-linux-gnu + - name: Add target + run: rustup target add ${{ matrix.target }} + - name: Setup rust toolchain + run: rustup show + - uses: Swatinem/rust-cache@v2 + with: + shared-key: build-then-release-${{ matrix.target }}-v1 + - name: Build + env: ${{ matrix.build_env }} + run: | + cargo build --release --target ${{ matrix.target }} + - name: Compress + run: | + zip -j dephy-decharge-controller-node-${{ needs.gen_version.outputs.version }}-${{ matrix.target }}.zip ./target/${{ matrix.target }}/release/dephy-decharge-controller-node && + zip -j dephy-decharge-controller-server-${{ needs.gen_version.outputs.version }}-${{ matrix.target }}.zip ./target/${{ matrix.target }}/release/dephy-decharge-controller-server && + zip -j dephy-gacha-controller-${{ needs.gen_version.outputs.version }}-${{ matrix.target }}.zip ./target/${{ matrix.target }}/release/dephy-gacha-controller + - uses: actions/upload-artifact@v4 + name: Upload artifacts + with: + name: dephy-vending-machine-examples-${{ needs.gen_version.outputs.version }}-${{ matrix.target }} + path: "*.zip" + retention-days: 1 + + release: + needs: [gen_version, build] + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - uses: actions/checkout@v4 + - name: Generate changelog + uses: orhun/git-cliff-action@v3 + id: git-cliff + with: + config: cliff.toml + args: "-vv --strip header ${{ needs.gen_version.outputs.version == 'prerelease' && '--unreleased' || '--latest' }}" + - uses: actions/download-artifact@v4 + - name: Display fetched artifacts + run: ls -R + - uses: softprops/action-gh-release@v2.0.6 + name: Emit a Github Release + with: + token: "${{ secrets.GITHUB_TOKEN }}" + body: "${{ steps.git-cliff.outputs.content }}" + tag_name: ${{ needs.gen_version.outputs.version }} + prerelease: ${{ needs.gen_version.outputs.version == 'prerelease' }} + files: | + LICENSE + dephy-vending-machine-examples-${{ needs.gen_version.outputs.version }}-x86_64-apple-darwin/*.zip + dephy-vending-machine-examples-${{ needs.gen_version.outputs.version }}-aarch64-apple-darwin/*.zip + dephy-vending-machine-examples-${{ needs.gen_version.outputs.version }}-x86_64-unknown-linux-musl/*.zip + dephy-vending-machine-examples-${{ needs.gen_version.outputs.version }}-aarch64-unknown-linux-musl/*.zip + + image: + needs: [gen_version, build] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: docker/setup-buildx-action@v3 + - uses: actions/download-artifact@v4 + - name: Log in to the Container registry + uses: docker/login-action@v3.3.0 + with: + username: ${{ vars.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Extract metadata for Docker + id: meta + uses: docker/metadata-action@v5.6.1 + with: + images: ${{ vars.DOCKERHUB_USERNAME }}/dephy-vending-machine-examples + - name: Extract all released executable files + run: | + for dir in dephy-vending-machine-examples-${{ needs.gen_version.outputs.version }}-*/; do + for zip_file in "$dir"*.zip; do + [ -f "$zip_file" ] && unzip "$zip_file" -d "$dir" && rm "$zip_file" + done + done + - name: Display fetched artifacts + run: ls -R + - name: Move directory for platforms + run: | + mkdir linux && + mv dephy-vending-machine-examples-${{ needs.gen_version.outputs.version }}-x86_64-unknown-linux-musl linux/amd64 && + mv dephy-vending-machine-examples-${{ needs.gen_version.outputs.version }}-aarch64-unknown-linux-musl linux/arm64 + - name: Display moved files + run: ls -R + - name: Build and push Docker image + id: push + uses: docker/build-push-action@v6.10.0 + with: + file: ./.github/dockerfiles/dephy-vending-machine-examples.dockerfile + context: . + platforms: linux/amd64,linux/arm64 + tags: ${{ steps.meta.outputs.tags }} + push: true diff --git a/dephy-vending_machine-examples/.github/workflows/check_and_test.yml b/dephy-vending_machine-examples/.github/workflows/check_and_test.yml new file mode 100644 index 0000000..a9755e1 --- /dev/null +++ b/dephy-vending_machine-examples/.github/workflows/check_and_test.yml @@ -0,0 +1,40 @@ +name: Check and test + +on: + push: + branches: + - main + pull_request: + branches: + - main + +env: + CARGO_TERM_COLOR: always + +jobs: + test: + name: Check and test + strategy: + matrix: + platform: [ubuntu-latest] + runs-on: ${{ matrix.platform }} + steps: + - uses: actions/checkout@v4 + - name: Setup rust toolchain + run: | + rustup install nightly + rustup component add rustfmt --toolchain nightly + rustup show + - name: Install nextest + uses: taiki-e/install-action@nextest + - uses: Swatinem/rust-cache@v2 + with: + shared-key: check-and-test-${{ matrix.platform }}-v1 + - name: Check code format + run: cargo +nightly fmt -- --check + - name: Check the package for errors + run: cargo check --all + - name: Lint rust sources + run: cargo clippy --all-targets --all-features --tests --benches -- -D warnings + - name: Execute rust tests + run: cargo nextest run --all-features --no-tests=pass diff --git a/dephy-vending_machine-examples/.gitignore b/dephy-vending_machine-examples/.gitignore new file mode 100644 index 0000000..f60c29a --- /dev/null +++ b/dephy-vending_machine-examples/.gitignore @@ -0,0 +1,13 @@ +.env +.DS_Store +target +.anchor +*.rs.bk +node_modules +test-ledger +.yarn +bun.lock +bun.lockb +package-lock.json +data +tmp diff --git a/dephy-vending_machine-examples/.pre-commit-config.yaml b/dephy-vending_machine-examples/.pre-commit-config.yaml new file mode 100644 index 0000000..688e9d0 --- /dev/null +++ b/dephy-vending_machine-examples/.pre-commit-config.yaml @@ -0,0 +1,54 @@ +fail_fast: false +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.6.0 + hooks: + - id: check-case-conflict + - id: check-merge-conflict + - id: check-symlinks + - id: check-yaml + - id: end-of-file-fixer + - id: fix-byte-order-marker + - id: mixed-line-ending + - id: trailing-whitespace + - repo: local + hooks: + - id: taplo + name: taplo format + description: Format Cargo.toml files with taplo. + entry: bash -c 'taplo format --check' + language: rust + files: Cargo.toml$ + - id: cargo-fmt + name: cargo fmt + description: Format files with rustfmt. + entry: bash -c 'cargo +nightly fmt -- --check' + language: rust + files: \.rs$ + - id: cargo-deny + name: cargo deny check + description: Check cargo dependencies + entry: bash -c 'cargo deny check -d' + language: rust + files: \.*$ + - id: typos + name: typos + description: check typo + entry: bash -c 'typos' + language: rust + files: \.*$ + pass_filenames: false + - id: cargo-check + name: cargo check + description: Check the package for errors. + entry: bash -c 'cargo check --all' + language: rust + files: \.rs$ + pass_filenames: false + - id: cargo-clippy + name: cargo clippy + description: Lint rust sources + entry: bash -c 'cargo clippy --all-targets --all-features --tests --benches -- -D warnings' + language: rust + files: \.rs$ + pass_filenames: false diff --git a/dephy-vending_machine-examples/.prettierignore b/dephy-vending_machine-examples/.prettierignore new file mode 100644 index 0000000..1c26229 --- /dev/null +++ b/dephy-vending_machine-examples/.prettierignore @@ -0,0 +1,9 @@ +.anchor +.DS_Store +target +node_modules +dist +build +test-ledger + +bun.lockb diff --git a/dephy-vending_machine-examples/Cargo.lock b/dephy-vending_machine-examples/Cargo.lock new file mode 100644 index 0000000..71bcf68 --- /dev/null +++ b/dephy-vending_machine-examples/Cargo.lock @@ -0,0 +1,7413 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "addr2line" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + +[[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 = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "getrandom 0.2.15", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "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-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[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 = "anstream" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" + +[[package]] +name = "anstyle-parse" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" +dependencies = [ + "anstyle", + "once_cell", + "windows-sys 0.59.0", +] + +[[package]] +name = "anyhow" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-std" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand 0.8.5", +] + +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[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-channel" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" +dependencies = [ + "concurrent-queue", + "event-listener 2.5.3", + "futures-core", +] + +[[package]] +name = "async-compression" +version = "0.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df895a515f70646414f4b45c0b79082783b80552b373a68283012928df56f522" +dependencies = [ + "brotli", + "flate2", + "futures-core", + "memchr", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "async-lock" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" +dependencies = [ + "event-listener 5.4.0", + "event-listener-strategy", + "pin-project-lite", +] + +[[package]] +name = "async-trait" +version = "0.1.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "644dd749086bf3771a2fbc5f256fdb982d53f011c7d5d560304eafeecebce79d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", +] + +[[package]] +name = "async-utility" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a34a3b57207a7a1007832416c3e4862378c8451b4e8e093e436f48c2d3d2c151" +dependencies = [ + "futures-util", + "gloo-timers", + "tokio", + "wasm-bindgen-futures", +] + +[[package]] +name = "async-wsocket" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34d2efbc332d581321b37a3012c942b0555483030b5cfc1325a95c386b11e27b" +dependencies = [ + "async-utility", + "futures", + "futures-util", + "js-sys", + "tokio", + "tokio-rustls 0.26.1", + "tokio-socks", + "tokio-tungstenite 0.24.0", + "url", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "atoi" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" +dependencies = [ + "num-traits", +] + +[[package]] +name = "atomic-destructor" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef49f5882e4b6afaac09ad239a4f8c70a24b8f2b0897edb1f706008efd109cf4" + +[[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.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "backtrace" +version = "0.3.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-targets 0.52.6", +] + +[[package]] +name = "base58ck" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c8d66485a3a2ea485c1913c4572ce0256067a5377ac8c75c4960e1cda98605f" +dependencies = [ + "bitcoin-internals 0.3.0", + "bitcoin_hashes 0.14.0", +] + +[[package]] +name = "base64" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" + +[[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.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "bech32" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d965446196e3b7decd44aa7ee49e31d630118f90ef12f97900f262eb915c951d" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bip39" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33415e24172c1b7d6066f6d999545375ab8e1d95421d6784bdfff9496f292387" +dependencies = [ + "bitcoin_hashes 0.13.0", + "serde", + "unicode-normalization", +] + +[[package]] +name = "bitcoin" +version = "0.32.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6bc65742dea50536e35ad42492b234c27904a27f0abdcbce605015cb4ea026" +dependencies = [ + "base58ck", + "bech32", + "bitcoin-internals 0.3.0", + "bitcoin-io", + "bitcoin-units", + "bitcoin_hashes 0.14.0", + "hex-conservative 0.2.1", + "hex_lit", + "secp256k1", + "serde", +] + +[[package]] +name = "bitcoin-internals" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9425c3bf7089c983facbae04de54513cce73b41c7f9ff8c845b54e7bc64ebbfb" + +[[package]] +name = "bitcoin-internals" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30bdbe14aa07b06e6cfeffc529a1f099e5fbe249524f8125358604df99a4bed2" +dependencies = [ + "serde", +] + +[[package]] +name = "bitcoin-io" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b47c4ab7a93edb0c7198c5535ed9b52b63095f4e9b45279c6736cec4b856baf" + +[[package]] +name = "bitcoin-units" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5285c8bcaa25876d07f37e3d30c303f2609179716e11d688f51e8f1fe70063e2" +dependencies = [ + "bitcoin-internals 0.3.0", + "serde", +] + +[[package]] +name = "bitcoin_hashes" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1930a4dabfebb8d7d9992db18ebe3ae2876f0a305fab206fd168df931ede293b" +dependencies = [ + "bitcoin-internals 0.2.0", + "hex-conservative 0.1.2", +] + +[[package]] +name = "bitcoin_hashes" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb18c03d0db0247e147a21a6faafd5a7eb851c743db062de72018b6b7e8e4d16" +dependencies = [ + "bitcoin-io", + "hex-conservative 0.2.1", + "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.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" +dependencies = [ + "serde", +] + +[[package]] +name = "blake3" +version = "1.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8ee0c1824c4dea5b5f81736aff91bae041d2c07ee1192bec91054e10e3e601e" +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 = [ + "generic-array", +] + +[[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 = "block-padding" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93" +dependencies = [ + "generic-array", +] + +[[package]] +name = "borsh" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115e54d64eb62cdebad391c19efc9dce4981c690c85a33a12199d99bb9546fee" +dependencies = [ + "borsh-derive 0.10.4", + "hashbrown 0.13.2", +] + +[[package]] +name = "borsh" +version = "1.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5430e3be710b68d984d1391c854eb431a9d548640711faa54eecb1df93db91cc" +dependencies = [ + "borsh-derive 1.5.5", + "cfg_aliases", +] + +[[package]] +name = "borsh-derive" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "831213f80d9423998dd696e2c5345aba6be7a0bd8cd19e31c5243e13df1cef89" +dependencies = [ + "borsh-derive-internal", + "borsh-schema-derive-internal", + "proc-macro-crate 0.1.5", + "proc-macro2", + "syn 1.0.109", +] + +[[package]] +name = "borsh-derive" +version = "1.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8b668d39970baad5356d7c83a86fee3a539e6f93bf6764c97368243e17a0487" +dependencies = [ + "once_cell", + "proc-macro-crate 3.2.0", + "proc-macro2", + "quote", + "syn 2.0.98", +] + +[[package]] +name = "borsh-derive-internal" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65d6ba50644c98714aa2a70d13d7df3cd75cd2b523a2b452bf010443800976b3" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "borsh-schema-derive-internal" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "276691d96f063427be83e6692b86148e488ebba9f48f77788724ca027ba3b6d4" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "brotli" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc97b8f16f944bba54f0433f07e30be199b6dc2bd25937444bbad560bcea29bd" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "4.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74fa05ad7d803d413eb8380983b092cbbaf9a85f151b871360e7b00cd7060b37" +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.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" + +[[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 = "bytemuck" +version = "1.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef657dfab802224e671f5818e9a4935f9b1957ed18e58292690cc39e7a4092a3" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fa76293b4f7bb636ab88fd78228235b5248b4d05cc589aed610f954af5d7c7a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f61dac84819c6588b558454b194026eb1f09c293b9036ae9b159e74e73ab6cf9" + +[[package]] +name = "caps" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "190baaad529bcfbde9e1a19022c42781bdb6ff9de25721abdb8fd98c0807730b" +dependencies = [ + "libc", + "thiserror 1.0.69", +] + +[[package]] +name = "cbc" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6" +dependencies = [ + "cipher", +] + +[[package]] +name = "cc" +version = "1.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7777341816418c02e033934a09f20dc0ccaf65a5201ef8a450ae0105a573fda" +dependencies = [ + "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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[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.98", +] + +[[package]] +name = "chacha20" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "chacha20poly1305" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10cd79432192d1c0f4e1a0fef9527696cc039165d729fb41b3f4f4f354c2dc35" +dependencies = [ + "aead", + "chacha20", + "cipher", + "poly1305", + "zeroize", +] + +[[package]] +name = "chrono" +version = "0.4.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "num-traits", + "serde", + "windows-targets 0.52.6", +] + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", + "zeroize", +] + +[[package]] +name = "clap" +version = "4.5.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8acebd8ad879283633b343856142139f2da2317c96b05b4dd6181c61e2480184" +dependencies = [ + "clap_builder", +] + +[[package]] +name = "clap_builder" +version = "4.5.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ba32cbda51c7e1dfd49acc1457ba1a7dec5b64fe360e828acb13ca8dc9c2f9" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_lex" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" + +[[package]] +name = "colorchoice" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" + +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + +[[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.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea3c6ecd8059b57859df5c69830340ed3c41d30e3da0c1cbed90a96ac853041b" +dependencies = [ + "encode_unicode", + "libc", + "once_cell", + "unicode-width", + "windows-sys 0.59.0", +] + +[[package]] +name = "console_error_panic_hook" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if", + "wasm-bindgen", +] + +[[package]] +name = "console_log" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89f72f65e8501878b8a004d5a1afb780987e2ce2b4532c562e367a72c57499f" +dependencies = [ + "log", + "web-sys", +] + +[[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.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.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 = "crc" +version = "3.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" + +[[package]] +name = "crc32fast" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471" +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-queue" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" +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 = "crunchy" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "typenum", +] + +[[package]] +name = "crypto-mac" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" +dependencies = [ + "generic-array", + "subtle", +] + +[[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 = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" +dependencies = [ + "byteorder", + "digest 0.9.0", + "rand_core 0.5.1", + "subtle", + "zeroize", +] + +[[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 0.10.7", + "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.98", +] + +[[package]] +name = "darling" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.98", +] + +[[package]] +name = "darling_macro" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.98", +] + +[[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.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "575f75dfd25738df5b91b8e43e14d44bda14637a58fae779fd2b064f8bf3e010" + +[[package]] +name = "dephy-balance-payment-sdk" +version = "0.1.0" +dependencies = [ + "arrayref", + "borsh 0.10.4", + "curve25519-dalek 4.1.3", + "num-derive", + "num-traits", + "serde", + "serde_json", + "serde_with", + "sha2 0.10.8", + "solana-client", + "solana-program", + "solana-sdk", + "solana-zk-token-sdk", + "thiserror 2.0.11", + "tracing", +] + +[[package]] +name = "dephy-decharge-controller" +version = "0.1.0" +dependencies = [ + "clap", + "dephy-balance-payment-sdk", + "futures", + "nostr", + "nostr-sdk", + "sea-query", + "sea-query-binder", + "serde", + "serde_json", + "sqlx", + "thiserror 2.0.11", + "tokio", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "dephy-gacha-controller" +version = "0.1.0" +dependencies = [ + "clap", + "dephy-balance-payment-sdk", + "futures", + "nostr", + "nostr-sdk", + "serde", + "serde_json", + "thiserror 2.0.11", + "tokio", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "der" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +dependencies = [ + "const-oid", + "pem-rfc7468", + "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.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", + "serde", +] + +[[package]] +name = "derivation-path" +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 = "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", + "const-oid", + "crypto-common", + "subtle", +] + +[[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.98", +] + +[[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.98", +] + +[[package]] +name = "dotenvy" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" + +[[package]] +name = "ed25519" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" +dependencies = [ + "signature 1.6.4", +] + +[[package]] +name = "ed25519-dalek" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" +dependencies = [ + "curve25519-dalek 3.2.0", + "ed25519", + "rand 0.7.3", + "serde", + "sha2 0.9.9", + "zeroize", +] + +[[package]] +name = "ed25519-dalek-bip32" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d2be62a4061b872c8c0873ee4fc6f101ce7b889d039f019c5fa2af471a59908" +dependencies = [ + "derivation-path", + "ed25519-dalek", + "hmac 0.12.1", + "sha2 0.10.8", +] + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +dependencies = [ + "serde", +] + +[[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 = "env_logger" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + +[[package]] +name = "etcetera" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" +dependencies = [ + "cfg-if", + "home", + "windows-sys 0.48.0", +] + +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + +[[package]] +name = "event-listener" +version = "5.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3492acde4c3fc54c845eaab3eed8bd00c7a7d881f78bfc801e43a93dec1331ae" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3e4e0dd3673c1139bf041f3008816d9cf2946bbfac2945c09e523b8d7b05b2" +dependencies = [ + "event-listener 5.4.0", + "pin-project-lite", +] + +[[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 = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + +[[package]] +name = "five8_const" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b4f62f0f8ca357f93ae90c8c2dd1041a1f665fde2f889ea9b1787903829015" +dependencies = [ + "five8_core", +] + +[[package]] +name = "five8_core" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94474d15a76982be62ca8a39570dccce148d98c238ebb7408b0a21b2c4bdddc4" + +[[package]] +name = "flate2" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "flume" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" +dependencies = [ + "futures-core", + "futures-sink", + "spin", +] + +[[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.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "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-intrusive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" +dependencies = [ + "futures-core", + "lock_api", + "parking_lot", +] + +[[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.98", +] + +[[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", +] + +[[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.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.13.3+wasi-0.2.2", + "windows-targets 0.52.6", +] + +[[package]] +name = "gimli" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" + +[[package]] +name = "gloo-timers" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + +[[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 = "h2" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http 0.2.12", + "indexmap 2.7.1", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash", +] + +[[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 = "hashlink" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" +dependencies = [ + "hashbrown 0.15.2", +] + +[[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.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hex-conservative" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212ab92002354b4819390025006c897e8140934349e8635c9b077f47b4dcbd20" + +[[package]] +name = "hex-conservative" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5313b072ce3c597065a808dbf612c4c8e8590bdbf8b579508bf7a762c5eae6cd" +dependencies = [ + "arrayvec", +] + +[[package]] +name = "hex_lit" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3011d1213f159867b13cfd6ac92d2cd5f1345762c63be3554e84092d85a50bbd" + +[[package]] +name = "histogram" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12cb882ccb290b8646e554b157ab0b71e64e8d5bef775cd66b6531e52d302669" + +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac 0.12.1", +] + +[[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.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589533453244b0995c858700322199b2becb13b627df2851f64a2775d024abcf" +dependencies = [ + "windows-sys 0.59.0", +] + +[[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.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" +dependencies = [ + "bytes", + "fnv", + "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 = "httparse" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2d708df4e7140240a16cd6ab0ab65c972d7433ab77819ea693fde9c43811e2a" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[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", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "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", + "rustls 0.21.12", + "tokio", + "tokio-rustls 0.24.1", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "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 = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", +] + +[[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.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + +[[package]] +name = "indexmap" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" +dependencies = [ + "equivalent", + "hashbrown 0.15.2", + "serde", +] + +[[package]] +name = "indicatif" +version = "0.17.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "183b3088984b400f4cfac3620d5e076c84da5364016b4f49473de574b2586235" +dependencies = [ + "console", + "number_prefix", + "portable-atomic", + "unicode-width", + "web-time", +] + +[[package]] +name = "inherent" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0122b7114117e64a63ac49f752a5ca4624d534c7b1c7de796ac196381cd2d947" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", +] + +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "block-padding", + "generic-array", +] + +[[package]] +name = "instant" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "ipnet" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" + +[[package]] +name = "jni" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6df18c2e3db7e453d3c6ac5b3e9d5182664d28788126d39b91f2d1e22b017ec" +dependencies = [ + "cesu8", + "combine", + "jni-sys", + "log", + "thiserror 1.0.69", + "walkdir", +] + +[[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.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +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 = "keccak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin", +] + +[[package]] +name = "libc" +version = "0.2.169" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" + +[[package]] +name = "libm" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" + +[[package]] +name = "libsecp256k1" +version = "0.6.0" +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", +] + +[[package]] +name = "libsecp256k1-core" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0f6ab710cec28cef759c5f18671a27dae2a5f952cdaaee1d8e2908cb2478a80" +dependencies = [ + "crunchy", + "digest 0.9.0", + "subtle", +] + +[[package]] +name = "libsecp256k1-gen-ecmult" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccab96b584d38fac86a83f07e659f0deafd0253dc096dab5a36d53efe653c5c3" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "libsecp256k1-gen-genmult" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67abfe149395e3aa1c48a2beb32b068e2334402df8181f818d3aee2b304c4f5d" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "libsqlite3-sys" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" +dependencies = [ + "pkg-config", + "vcpkg", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" + +[[package]] +name = "litemap" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" + +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + +[[package]] +name = "md-5" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +dependencies = [ + "cfg-if", + "digest 0.10.7", +] + +[[package]] +name = "memchr" +version = "2.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" +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.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3b1c9bd4fe1f0f8b387f6eb9eb3b4a1aa26185e5750efb9140301703f62cd1b" +dependencies = [ + "adler2", +] + +[[package]] +name = "mio" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" +dependencies = [ + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.52.0", +] + +[[package]] +name = "negentropy" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e664971378a3987224f7a0e10059782035e89899ae403718ee07de85bec42afe" + +[[package]] +name = "negentropy" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a88da9dd148bbcdce323dd6ac47d369b4769d4a3b78c6c52389b9269f77932" + +[[package]] +name = "nix" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +dependencies = [ + "bitflags 2.8.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 = "nostr" +version = "0.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af7c1eebe17dd785e52e1f81149c1b50fa6ec92e4ac239840934d1ffbd4f631c" +dependencies = [ + "async-trait", + "base64 0.22.1", + "bech32", + "bip39", + "bitcoin", + "cbc", + "chacha20", + "chacha20poly1305", + "getrandom 0.2.15", + "instant", + "negentropy 0.3.1", + "negentropy 0.4.3", + "once_cell", + "scrypt", + "serde", + "serde_json", + "unicode-normalization", + "url", +] + +[[package]] +name = "nostr-database" +version = "0.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c175f769291b39e399905c1e1f0dcde0ea4959642db50a9a97f47fe73fac947" +dependencies = [ + "async-trait", + "nostr", + "tokio", +] + +[[package]] +name = "nostr-relay-pool" +version = "0.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0a11b3d117d729b32efffacf7566ec6845e96e836cfab32c61b818cf90f8e4" +dependencies = [ + "async-utility", + "async-wsocket", + "atomic-destructor", + "negentropy 0.3.1", + "negentropy 0.4.3", + "nostr", + "nostr-database", + "tokio", + "tracing", +] + +[[package]] +name = "nostr-sdk" +version = "0.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce4741c6b4bcb46fe5fdf6834c64b2d8aee090264319aa4749f268e20ace111" +dependencies = [ + "async-utility", + "nostr", + "nostr-database", + "nostr-relay-pool", + "tokio", + "tracing", +] + +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + +[[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-bigint-dig" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" +dependencies = [ + "byteorder", + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand 0.8.5", + "smallvec", + "zeroize", +] + +[[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.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[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.98", +] + +[[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", + "libm", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi 0.3.9", + "libc", +] + +[[package]] +name = "num_enum" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" +dependencies = [ + "proc-macro-crate 3.2.0", + "proc-macro2", + "quote", + "syn 2.0.98", +] + +[[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.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +dependencies = [ + "memchr", +] + +[[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.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e" + +[[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.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61cfb4e166a8bb8c9b55c500bc2308550148ece889be90f609377e58140f42c6" +dependencies = [ + "bitflags 2.8.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.98", +] + +[[package]] +name = "openssl-probe" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" + +[[package]] +name = "openssl-src" +version = "300.4.1+3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faa4eac4138c62414b5622d1b31c5c304f34b406b013c079c2bbc652fdd6678c" +dependencies = [ + "cc", +] + +[[package]] +name = "openssl-sys" +version = "0.9.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b22d5b84be05a8d6947c7cb71f7c849aa0f112acd4bf51c2a7c1c988ac0a9dc" +dependencies = [ + "cc", + "libc", + "openssl-src", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + +[[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.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.52.6", +] + +[[package]] +name = "password-hash" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" +dependencies = [ + "base64ct", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "pbkdf2" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" +dependencies = [ + "digest 0.10.7", + "hmac 0.12.1", +] + +[[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 = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[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-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 = "pkcs1" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" +dependencies = [ + "der", + "pkcs8", + "spki", +] + +[[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.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" + +[[package]] +name = "poly1305" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8159bd90725d2df49889a078b54f4f79e87f1f8a8444194cdca81d38f5393abf" +dependencies = [ + "cpufeatures", + "opaque-debug", + "universal-hash", +] + +[[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.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "280dc24453071f1b63954171985a0b0d30058d287960968b9b2aca264c8d4ee6" + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro-crate" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" +dependencies = [ + "toml", +] + +[[package]] +name = "proc-macro-crate" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro2" +version = "1.0.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" +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.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bd1fe6824cea6538803de3ff1bc0cf3949024db3d43c9643024bfb33a807c0e" +dependencies = [ + "crossbeam-utils", + "libc", + "once_cell", + "raw-cpuid", + "wasi 0.11.0+wasi-snapshot-preview1", + "web-sys", + "winapi", +] + +[[package]] +name = "quinn" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62e96808277ec6f97351a2380e6c25114bc9e67037775464979f3037c92d05ef" +dependencies = [ + "bytes", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls 0.23.23", + "socket2", + "thiserror 2.0.11", + "tokio", + "tracing", +] + +[[package]] +name = "quinn-proto" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2fe5ef3495d7d2e377ff17b1a8ce2ee2ec2a18cde8b6ad6619d65d0701c135d" +dependencies = [ + "bytes", + "getrandom 0.2.15", + "rand 0.8.5", + "ring", + "rustc-hash", + "rustls 0.23.23", + "rustls-pki-types", + "rustls-platform-verifier", + "slab", + "thiserror 2.0.11", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c40286217b4ba3a71d644d752e6a0b71f13f1b6a2c5311acfcbe0c2418ed904" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.59.0", +] + +[[package]] +name = "quote" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.7.3" +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", +] + +[[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_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", +] + +[[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_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.15", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "raw-cpuid" +version = "11.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6928fa44c097620b706542d428957635951bade7143269085389d42c8a4927e" +dependencies = [ + "bitflags 2.8.0", +] + +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "redox_syscall" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" +dependencies = [ + "bitflags 2.8.0", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata 0.4.9", + "regex-syntax 0.8.5", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.8.5", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "reqwest" +version = "0.11.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" +dependencies = [ + "async-compression", + "base64 0.21.7", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http 0.2.12", + "http-body", + "hyper", + "hyper-rustls", + "ipnet", + "js-sys", + "log", + "mime", + "mime_guess", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls 0.21.12", + "rustls-pemfile 1.0.4", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "system-configuration", + "tokio", + "tokio-rustls 0.24.1", + "tokio-util", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots 0.25.4", + "winreg", +] + +[[package]] +name = "reqwest-middleware" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a735987236a8e238bf0296c7e351b999c188ccc11477f311b82b55c93984216" +dependencies = [ + "anyhow", + "async-trait", + "http 0.2.12", + "reqwest", + "serde", + "task-local-extensions", + "thiserror 1.0.69", +] + +[[package]] +name = "ring" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.15", + "libc", + "spin", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rsa" +version = "0.9.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47c75d7c5c6b673e58bf54d8544a9f432e3a925b0e80f7cd3602ab5c50c55519" +dependencies = [ + "const-oid", + "digest 0.10.7", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core 0.6.4", + "signature 2.2.0", + "spki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[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 = "0.38.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +dependencies = [ + "bitflags 2.8.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.59.0", +] + +[[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.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47796c98c480fce5406ef69d1c76378375492c3b0a0de587be0c1d9feb12f395" +dependencies = [ + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki 0.102.8", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-native-certs" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5" +dependencies = [ + "openssl-probe", + "rustls-pemfile 2.2.0", + "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-pemfile" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c" +dependencies = [ + "web-time", +] + +[[package]] +name = "rustls-platform-verifier" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4c7dc240fec5517e6c4eab3310438636cfe6391dfc345ba013109909a90d136" +dependencies = [ + "core-foundation", + "core-foundation-sys", + "jni", + "log", + "once_cell", + "rustls 0.23.23", + "rustls-native-certs", + "rustls-platform-verifier-android", + "rustls-webpki 0.102.8", + "security-framework", + "security-framework-sys", + "webpki-root-certs", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustls-platform-verifier-android" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" + +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "rustls-webpki" +version = "0.102.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" + +[[package]] +name = "ryu" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd" + +[[package]] +name = "salsa20" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" +dependencies = [ + "cipher", +] + +[[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.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "scrypt" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0516a385866c09368f0b5bcd1caff3366aace790fcd46e2bb032697bb172fd1f" +dependencies = [ + "password-hash", + "pbkdf2 0.12.2", + "salsa20", + "sha2 0.10.8", +] + +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "sea-query" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "085e94f7d7271c0393ac2d164a39994b1dff1b06bc40cd9a0da04f3d672b0fee" +dependencies = [ + "inherent", + "sea-query-derive", +] + +[[package]] +name = "sea-query-binder" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0019f47430f7995af63deda77e238c17323359af241233ec768aba1faea7608" +dependencies = [ + "sea-query", + "sqlx", +] + +[[package]] +name = "sea-query-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9834af2c4bd8c5162f00c89f1701fb6886119a88062cf76fe842ea9e232b9839" +dependencies = [ + "darling", + "heck 0.4.1", + "proc-macro2", + "quote", + "syn 2.0.98", + "thiserror 1.0.69", +] + +[[package]] +name = "secp256k1" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9465315bc9d4566e1724f0fffcbcc446268cb522e60f9a27bcded6b19c108113" +dependencies = [ + "bitcoin_hashes 0.14.0", + "rand 0.8.5", + "secp256k1-sys", + "serde", +] + +[[package]] +name = "secp256k1-sys" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4387882333d3aa8cb20530a17c69a3752e97837832f34f6dccc760e715001d9" +dependencies = [ + "cc", +] + +[[package]] +name = "security-framework" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +dependencies = [ + "bitflags 2.8.0", + "core-foundation", + "core-foundation-sys", + "libc", + "num-bigint 0.4.6", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f79dfe2d285b0488816f30e700a7438c5a73d816b5b7d3ac72fbc48b0d185e03" + +[[package]] +name = "serde" +version = "1.0.217" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" +dependencies = [ + "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.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "387cc504cb06bb40a96c8e04e951fe01854cf6bc921053c954e4a606d9675c6a" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.217" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", +] + +[[package]] +name = "serde_json" +version = "1.0.138" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d434192e7da787e94a6ea7e9670b26a036d0ca41e0b7efb2676dd32bae872949" +dependencies = [ + "indexmap 2.7.1", + "itoa", + "memchr", + "ryu", + "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.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6b6f7f2fcb69f747921f79f3926bd1e203fce4fef62c268dd3abfb6d86029aa" +dependencies = [ + "base64 0.22.1", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.7.1", + "serde", + "serde_derive", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d00caa5193a3c8362ac2b73be6b9e768aa5a4b2f721d8f4b339600c3cb51f8e" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.98", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +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", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest 0.10.7", + "keccak", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[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.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +dependencies = [ + "libc", +] + +[[package]] +name = "signature" +version = "1.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest 0.10.7", + "rand_core 0.6.4", +] + +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +dependencies = [ + "serde", +] + +[[package]] +name = "socket2" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "solana-account" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8921f616711771b71d4828f741c41d0cc6ab20937f62434b92335acf0c328f11" +dependencies = [ + "bincode", + "serde", + "serde_bytes", + "serde_derive", + "solana-account-info", + "solana-clock", + "solana-instruction", + "solana-pubkey", + "solana-sdk-ids", + "solana-sysvar", +] + +[[package]] +name = "solana-account-decoder-client-types" +version = "2.2.0" +source = "git+https://github.com/anza-xyz/agave.git?branch=v2.2#f5c162cbfcc03985f63c0603086194277124e88b" +dependencies = [ + "base64 0.22.1", + "bs58", + "serde", + "serde_derive", + "serde_json", + "solana-account", + "solana-pubkey", + "zstd", +] + +[[package]] +name = "solana-account-info" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5d3d8a883f0e6928427a2dcceeb33ec7d87c47ec349a78d446a8357acc415cf" +dependencies = [ + "bincode", + "serde", + "solana-program-error", + "solana-program-memory", + "solana-pubkey", +] + +[[package]] +name = "solana-address-lookup-table-interface" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04f002d5b24d29a0a9ceb7fad82a7fcad5f68b2b1c04b4dd1fe514a4ee634a50" +dependencies = [ + "bincode", + "bytemuck", + "serde", + "serde_derive", + "solana-clock", + "solana-instruction", + "solana-pubkey", + "solana-sdk-ids", + "solana-slot-hashes", +] + +[[package]] +name = "solana-atomic-u64" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180aa1d8a66a709cf6e1ed030607e20c1db8b542ee864c6d4cf33d43fea338e5" +dependencies = [ + "parking_lot", +] + +[[package]] +name = "solana-big-mod-exp" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b28c7604fe6e94ce5d05c8f9d171a57adc707f908731bda74c18645391c398a" +dependencies = [ + "num-bigint 0.4.6", + "num-traits", + "solana-define-syscall", +] + +[[package]] +name = "solana-bincode" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5077f558a6fa420a30e1552824fa3c7e80f69429c5bfa60480362f1de4ef985" +dependencies = [ + "bincode", + "serde", + "solana-instruction", +] + +[[package]] +name = "solana-blake3-hasher" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb9a054858932c63a4c96cbe1a8fae8770e79dfe2d0bf07e0b26d03ebc6403ca" +dependencies = [ + "blake3", + "solana-define-syscall", + "solana-hash", + "solana-sanitize", +] + +[[package]] +name = "solana-bn254" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d25219261a38b268f97aea960f35ee7e9dc087c269d0952aa5c3e3aad8b735f" +dependencies = [ + "ark-bn254", + "ark-ec", + "ark-ff", + "ark-serialize", + "bytemuck", + "solana-define-syscall", + "thiserror 2.0.11", +] + +[[package]] +name = "solana-borsh" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bd8ebd23d44ddfb3b6cb887499ceae1fea0c1dc63fc1a441a8b82192185f4b7" +dependencies = [ + "borsh 0.10.4", + "borsh 1.5.5", +] + +[[package]] +name = "solana-client" +version = "2.2.0" +source = "git+https://github.com/anza-xyz/agave.git?branch=v2.2#f5c162cbfcc03985f63c0603086194277124e88b" +dependencies = [ + "async-trait", + "bincode", + "dashmap", + "futures", + "futures-util", + "indexmap 2.7.1", + "indicatif", + "log", + "quinn", + "rayon", + "solana-account", + "solana-client-traits", + "solana-commitment-config", + "solana-connection-cache", + "solana-epoch-info", + "solana-hash", + "solana-instruction", + "solana-keypair", + "solana-measure", + "solana-message", + "solana-pubkey", + "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-thin-client", + "solana-time-utils", + "solana-tpu-client", + "solana-transaction", + "solana-transaction-error", + "solana-udp-client", + "thiserror 2.0.11", + "tokio", +] + +[[package]] +name = "solana-client-traits" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ae616269c74fe3e8f0193a631513057074d54d753605685afca7f0421cfb844" +dependencies = [ + "solana-account", + "solana-commitment-config", + "solana-epoch-info", + "solana-hash", + "solana-instruction", + "solana-keypair", + "solana-message", + "solana-pubkey", + "solana-signature", + "solana-signer", + "solana-system-interface", + "solana-transaction", + "solana-transaction-error", +] + +[[package]] +name = "solana-clock" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ee21be92dbcfc3240536fa9615bf5418db2e373d3ba794baf3c63d8d17d85aa" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-sysvar-id", +] + +[[package]] +name = "solana-cluster-type" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be3d6c005c60c9895c9beeaa4d157ffeba4dcd2eea6cada3ba4edcc0a3ece39f" +dependencies = [ + "serde", + "serde_derive", + "solana-hash", +] + +[[package]] +name = "solana-commitment-config" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fef9ace627762305f68784868f1ecaea2bccb5dc658850d6a9f1818fbcecadc" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "solana-compute-budget-interface" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcf6f360539a44a5e2f27aded0696b64799e57dd6678423fb5f40b4433940cea" +dependencies = [ + "borsh 1.5.5", + "serde", + "serde_derive", + "solana-instruction", + "solana-sdk-ids", +] + +[[package]] +name = "solana-connection-cache" +version = "2.2.0" +source = "git+https://github.com/anza-xyz/agave.git?branch=v2.2#f5c162cbfcc03985f63c0603086194277124e88b" +dependencies = [ + "async-trait", + "bincode", + "crossbeam-channel", + "futures-util", + "indexmap 2.7.1", + "log", + "rand 0.8.5", + "rayon", + "solana-keypair", + "solana-measure", + "solana-metrics", + "solana-net-utils", + "solana-time-utils", + "solana-transaction-error", + "thiserror 2.0.11", + "tokio", +] + +[[package]] +name = "solana-cpi" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be0ef159507ece00b3ae2e6c68055fb1ebe161d1c22ba0f33041ba3eb1a21eb3" +dependencies = [ + "solana-account-info", + "solana-define-syscall", + "solana-instruction", + "solana-program-error", + "solana-pubkey", + "solana-stable-layout", +] + +[[package]] +name = "solana-curve25519" +version = "2.2.0" +source = "git+https://github.com/anza-xyz/agave.git?branch=v2.2#f5c162cbfcc03985f63c0603086194277124e88b" +dependencies = [ + "bytemuck", + "bytemuck_derive", + "curve25519-dalek 4.1.3", + "solana-define-syscall", + "subtle", + "thiserror 2.0.11", +] + +[[package]] +name = "solana-decode-error" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2249dcb5383b8f91777475eaffb71192be5ffa2b2f7ef34b89b4fa2975f0bed" +dependencies = [ + "num-traits", +] + +[[package]] +name = "solana-define-syscall" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acfe725269aac42d044cca5a99cfe8bd3b3f10e8d429b51f0c274e434fb34556" + +[[package]] +name = "solana-derivation-path" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6f0b5beefd88b57fabb7d83fa4239e3dcddb779244f81488a800f5e09ba187c" +dependencies = [ + "derivation-path", + "qstring", + "uriparse", +] + +[[package]] +name = "solana-ed25519-program" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d1a61c5e5f1dae28957daabf1809c918700d0ad9ddc5c43b4b85e30ad445b7d" +dependencies = [ + "bytemuck", + "bytemuck_derive", + "ed25519-dalek", + "solana-feature-set", + "solana-instruction", + "solana-precompile-error", + "solana-sdk-ids", +] + +[[package]] +name = "solana-epoch-info" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fff88883795bc1cde6e089d10ce87d9abe78614317408c67b9e98b7e6e7fe680" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "solana-epoch-rewards" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6519f3178a03bbb7d36c0068f4276293de8b81aa87d15f11b2f9968778bbe84d" +dependencies = [ + "serde", + "serde_derive", + "solana-hash", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-sysvar-id", +] + +[[package]] +name = "solana-epoch-rewards-hasher" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1781e2555534e7cf57fd7832b06118f42ea6519d31b03afc90ff1932fe831681" +dependencies = [ + "siphasher", + "solana-hash", + "solana-pubkey", +] + +[[package]] +name = "solana-epoch-schedule" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c616297c19a097a8f718c0abff0f23c0f80baccaddc24306a1b4701b0e5af60" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-sysvar-id", +] + +[[package]] +name = "solana-example-mocks" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f024993f59c085cde2c265a87035b139221c168266c51e1ef2c0c817d14172f" +dependencies = [ + "serde", + "serde_derive", + "solana-address-lookup-table-interface", + "solana-clock", + "solana-hash", + "solana-instruction", + "solana-keccak-hasher", + "solana-message", + "solana-nonce", + "solana-pubkey", + "solana-sdk-ids", + "solana-system-interface", + "thiserror 2.0.11", +] + +[[package]] +name = "solana-feature-gate-interface" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c1880be2f4b4f94c58338e081cea0fd8e5381c73b60272ca6746af277c74bb1" +dependencies = [ + "bincode", + "serde", + "serde_derive", + "solana-account", + "solana-account-info", + "solana-instruction", + "solana-program-error", + "solana-pubkey", + "solana-rent", + "solana-sdk-ids", + "solana-system-interface", +] + +[[package]] +name = "solana-feature-set" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c64433def9f89551638460ab3443a2b72fb91f4f0cf9b79e7f56345068f60e2d" +dependencies = [ + "ahash", + "lazy_static", + "solana-epoch-schedule", + "solana-hash", + "solana-pubkey", + "solana-sha256-hasher", +] + +[[package]] +name = "solana-fee-calculator" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6efed4a994807173cc48c66c5983c5b965dc4e27ee8b85c21290eb6178cc342" +dependencies = [ + "log", + "serde", + "serde_derive", +] + +[[package]] +name = "solana-fee-structure" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "051c6d8c8b35b4c302e4de0a9c2dff9178a400611179002210edcb053fb4c86d" +dependencies = [ + "serde", + "serde_derive", + "solana-message", + "solana-native-token", +] + +[[package]] +name = "solana-genesis-config" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26551a9c57b499b7aef4fae92748ba2329a168b3e9b8fce6a3f22dbb2ef4e05c" +dependencies = [ + "bincode", + "chrono", + "memmap2", + "serde", + "serde_derive", + "solana-account", + "solana-clock", + "solana-cluster-type", + "solana-epoch-schedule", + "solana-fee-calculator", + "solana-hash", + "solana-inflation", + "solana-keypair", + "solana-logger", + "solana-native-token", + "solana-poh-config", + "solana-pubkey", + "solana-rent", + "solana-sdk-ids", + "solana-sha256-hasher", + "solana-shred-version", + "solana-signer", + "solana-time-utils", +] + +[[package]] +name = "solana-hard-forks" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ad74d3fe543f080551d479da3bcd0b982508ec2d5c38a0c79c76684cfef0aa0" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "solana-hash" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7e29a5aba505e381c8251d2b7c4f87676ede47f874f676b82c897309c79fca" +dependencies = [ + "borsh 1.5.5", + "bs58", + "bytemuck", + "bytemuck_derive", + "js-sys", + "serde", + "serde_derive", + "solana-atomic-u64", + "solana-sanitize", + "wasm-bindgen", +] + +[[package]] +name = "solana-inflation" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b71a542351ed9d79de87dadaff20cb2e9bb28d608418b4f6355f0bd8d5e09d94" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "solana-inline-spl" +version = "2.2.0" +source = "git+https://github.com/anza-xyz/agave.git?branch=v2.2#f5c162cbfcc03985f63c0603086194277124e88b" +dependencies = [ + "bytemuck", + "solana-pubkey", +] + +[[package]] +name = "solana-instruction" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "203a473c569413392fcbae76e7c0cc316384f2231d22314a0e45f8bf49fdf33b" +dependencies = [ + "bincode", + "borsh 1.5.5", + "getrandom 0.2.15", + "js-sys", + "num-traits", + "serde", + "serde_derive", + "solana-define-syscall", + "solana-pubkey", + "wasm-bindgen", +] + +[[package]] +name = "solana-instructions-sysvar" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6da5b2a406cb19ac7833cfe784d8084a146816ea30388bda39fd53ab2db8857a" +dependencies = [ + "bitflags 2.8.0", + "solana-account-info", + "solana-instruction", + "solana-program-error", + "solana-pubkey", + "solana-sanitize", + "solana-sdk-ids", + "solana-serialize-utils", + "solana-sysvar-id", +] + +[[package]] +name = "solana-keccak-hasher" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5f21b6ebb03ac2dcfb39a89f6d3c1f5c90498acb7679c613cb1eaad6e2f70c9" +dependencies = [ + "sha3", + "solana-define-syscall", + "solana-hash", + "solana-sanitize", +] + +[[package]] +name = "solana-keypair" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4204e3120e9a568bb148759367f2adeca0e1ad32de52aab641b113fd2f8735c3" +dependencies = [ + "bs58", + "ed25519-dalek", + "ed25519-dalek-bip32", + "rand 0.7.3", + "solana-derivation-path", + "solana-pubkey", + "solana-seed-derivable", + "solana-seed-phrase", + "solana-signature", + "solana-signer", + "wasm-bindgen", +] + +[[package]] +name = "solana-last-restart-slot" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37ba8f2feb1a64f46a65ad0c86582c0a62d664480be04ca51f1f0aed525a86b9" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-sysvar-id", +] + +[[package]] +name = "solana-loader-v2-interface" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93ae2d3ab2587687b807747e06be802c34cd4187013b3de9053431db30cc7fb8" +dependencies = [ + "serde", + "serde_bytes", + "serde_derive", + "solana-instruction", + "solana-pubkey", + "solana-sdk-ids", +] + +[[package]] +name = "solana-loader-v3-interface" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "feef12d4276f615604a36a3ae2088164fd5fffee487e1e62318751c7550a4f63" +dependencies = [ + "serde", + "serde_bytes", + "serde_derive", + "solana-instruction", + "solana-pubkey", + "solana-sdk-ids", + "solana-system-interface", +] + +[[package]] +name = "solana-loader-v4-interface" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7106bc1ec1edf234c99c85e4a8cd8978ccb91ebfd69f9b86e5fad8378c4f9a17" +dependencies = [ + "serde", + "serde_bytes", + "serde_derive", + "solana-instruction", + "solana-pubkey", + "solana-sdk-ids", + "solana-system-interface", +] + +[[package]] +name = "solana-logger" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84cfc2f547fee3ee1bd91b0d3afcb04d9d8a6ed5a14d64274cfdc68c340020f6" +dependencies = [ + "env_logger", + "lazy_static", + "log", +] + +[[package]] +name = "solana-measure" +version = "2.2.0" +source = "git+https://github.com/anza-xyz/agave.git?branch=v2.2#f5c162cbfcc03985f63c0603086194277124e88b" + +[[package]] +name = "solana-message" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0956ed485c297d9a472652e607b34f010dec33f91c7d20e80aa91bf92e8ec169" +dependencies = [ + "bincode", + "blake3", + "lazy_static", + "serde", + "serde_derive", + "solana-bincode", + "solana-hash", + "solana-instruction", + "solana-pubkey", + "solana-sanitize", + "solana-sdk-ids", + "solana-short-vec", + "solana-system-interface", + "solana-transaction-error", + "wasm-bindgen", +] + +[[package]] +name = "solana-metrics" +version = "2.2.0" +source = "git+https://github.com/anza-xyz/agave.git?branch=v2.2#f5c162cbfcc03985f63c0603086194277124e88b" +dependencies = [ + "crossbeam-channel", + "gethostname", + "lazy_static", + "log", + "reqwest", + "solana-clock", + "solana-cluster-type", + "solana-sha256-hasher", + "solana-time-utils", + "thiserror 2.0.11", +] + +[[package]] +name = "solana-msg" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b17b5e3bebc5d8c8e64c2db7e42aac0232290833c8c28cb3c45ee383f1a237d" +dependencies = [ + "solana-define-syscall", +] + +[[package]] +name = "solana-native-token" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f51c5e81d3dda6bb68668c23bb8d591518fbbcdaccc8673dcc44a773f049622a" + +[[package]] +name = "solana-net-utils" +version = "2.2.0" +source = "git+https://github.com/anza-xyz/agave.git?branch=v2.2#f5c162cbfcc03985f63c0603086194277124e88b" +dependencies = [ + "anyhow", + "bincode", + "bytes", + "crossbeam-channel", + "itertools 0.12.1", + "log", + "nix", + "rand 0.8.5", + "serde", + "serde_derive", + "socket2", + "solana-serde", + "tokio", + "url", +] + +[[package]] +name = "solana-nonce" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d9d856214dfd16804d11008537ae10320577b65828b8eae5bd9b1f065d3f8b" +dependencies = [ + "serde", + "serde_derive", + "solana-fee-calculator", + "solana-hash", + "solana-pubkey", + "solana-sha256-hasher", +] + +[[package]] +name = "solana-nonce-account" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d9836c27351b21c46b187b6196f531815ba1dcab007b60fd576784b611517a" +dependencies = [ + "solana-account", + "solana-hash", + "solana-nonce", + "solana-sdk-ids", +] + +[[package]] +name = "solana-offchain-message" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d9306d45394521335d6b8f8b8d6b333526da2f44d7e9c39b32ffe61f763015c" +dependencies = [ + "num_enum", + "solana-hash", + "solana-packet", + "solana-pubkey", + "solana-sanitize", + "solana-sha256-hasher", + "solana-signature", + "solana-signer", +] + +[[package]] +name = "solana-packet" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b49f415630073dd29449f5555a88165e5dc3fc91fe105252bcab08c3ae30f732" +dependencies = [ + "bincode", + "bitflags 2.8.0", + "cfg_eval", + "serde", + "serde_derive", + "serde_with", +] + +[[package]] +name = "solana-perf" +version = "2.2.0" +source = "git+https://github.com/anza-xyz/agave.git?branch=v2.2#f5c162cbfcc03985f63c0603086194277124e88b" +dependencies = [ + "ahash", + "bincode", + "bv", + "caps", + "curve25519-dalek 4.1.3", + "dlopen2", + "fnv", + "lazy_static", + "libc", + "log", + "nix", + "rand 0.8.5", + "rayon", + "serde", + "solana-hash", + "solana-message", + "solana-metrics", + "solana-packet", + "solana-pubkey", + "solana-rayon-threadlimit", + "solana-sdk-ids", + "solana-short-vec", + "solana-signature", + "solana-time-utils", +] + +[[package]] +name = "solana-poh-config" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f8f49e59491a9c3210b97f8277ef9bf814073883b7a324b927f00163edc27f4" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "solana-precompile-error" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68bed837597986ab0f44eea3240e2a09c09004516c27274d24450da8f9d84eb5" +dependencies = [ + "num-traits", + "solana-decode-error", +] + +[[package]] +name = "solana-precompiles" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbedabd76bfd8a718561510e88d87e94ebc575324a56b3480ee50c9cdf618fdf" +dependencies = [ + "lazy_static", + "solana-ed25519-program", + "solana-feature-set", + "solana-message", + "solana-precompile-error", + "solana-pubkey", + "solana-sdk-ids", + "solana-secp256k1-program", + "solana-secp256r1-program", +] + +[[package]] +name = "solana-presigner" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dcfaeef4597fdca40172bd1eeba1247239e61c156db05529fe31d3df889e3b8" +dependencies = [ + "solana-pubkey", + "solana-signature", + "solana-signer", +] + +[[package]] +name = "solana-program" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49e3353ad06f95d4624bffc9cf01fc9f9ac4566977df6ece3175fd2119834025" +dependencies = [ + "bincode", + "blake3", + "borsh 0.10.4", + "borsh 1.5.5", + "bs58", + "bytemuck", + "console_error_panic_hook", + "console_log", + "getrandom 0.2.15", + "lazy_static", + "log", + "memoffset", + "num-bigint 0.4.6", + "num-derive", + "num-traits", + "rand 0.8.5", + "serde", + "serde_bytes", + "serde_derive", + "solana-account-info", + "solana-address-lookup-table-interface", + "solana-atomic-u64", + "solana-big-mod-exp", + "solana-bincode", + "solana-blake3-hasher", + "solana-borsh", + "solana-clock", + "solana-cpi", + "solana-decode-error", + "solana-define-syscall", + "solana-epoch-rewards", + "solana-epoch-schedule", + "solana-example-mocks", + "solana-feature-gate-interface", + "solana-fee-calculator", + "solana-hash", + "solana-instruction", + "solana-instructions-sysvar", + "solana-keccak-hasher", + "solana-last-restart-slot", + "solana-loader-v2-interface", + "solana-loader-v3-interface", + "solana-loader-v4-interface", + "solana-message", + "solana-msg", + "solana-native-token", + "solana-nonce", + "solana-program-entrypoint", + "solana-program-error", + "solana-program-memory", + "solana-program-option", + "solana-program-pack", + "solana-pubkey", + "solana-rent", + "solana-sanitize", + "solana-sdk-ids", + "solana-sdk-macro", + "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-stake-interface", + "solana-system-interface", + "solana-sysvar", + "solana-sysvar-id", + "solana-vote-interface", + "thiserror 2.0.11", + "wasm-bindgen", +] + +[[package]] +name = "solana-program-entrypoint" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e8ac729923675be5ff5184b68f8d27bfd617b3f82bed2b2147f81fe9cda71f" +dependencies = [ + "solana-account-info", + "solana-msg", + "solana-program-error", + "solana-pubkey", +] + +[[package]] +name = "solana-program-error" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2cbf136a27d9bbc680a94e289f1c07498d271685a1711e00261ceebe740c5dc" +dependencies = [ + "borsh 1.5.5", + "num-traits", + "serde", + "serde_derive", + "solana-decode-error", + "solana-instruction", + "solana-msg", + "solana-pubkey", +] + +[[package]] +name = "solana-program-memory" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df359a8ddd2dfc8a5b2052b26b0c7099fa74419120a2b7ac639f47da0ced7ebc" +dependencies = [ + "num-traits", + "solana-define-syscall", +] + +[[package]] +name = "solana-program-option" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f9a5b3439dbec9038519fc5d58d51d8ee57e38914ed2fc0627ab0e5e142e536" + +[[package]] +name = "solana-program-pack" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c16896889ff0eb5cee67e5eb1c5f4247e56bca4b635ebd85a163dae8ffec2ced" +dependencies = [ + "solana-program-error", +] + +[[package]] +name = "solana-pubkey" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef5eb2846bcb028107c3979316501205c70fa64789214b5af85752fee61e7279" +dependencies = [ + "borsh 0.10.4", + "borsh 1.5.5", + "bs58", + "bytemuck", + "bytemuck_derive", + "curve25519-dalek 4.1.3", + "five8_const", + "getrandom 0.2.15", + "js-sys", + "num-traits", + "rand 0.8.5", + "serde", + "serde_derive", + "solana-atomic-u64", + "solana-decode-error", + "solana-define-syscall", + "solana-sanitize", + "solana-sha256-hasher", + "wasm-bindgen", +] + +[[package]] +name = "solana-pubsub-client" +version = "2.2.0" +source = "git+https://github.com/anza-xyz/agave.git?branch=v2.2#f5c162cbfcc03985f63c0603086194277124e88b" +dependencies = [ + "crossbeam-channel", + "futures-util", + "log", + "reqwest", + "semver", + "serde", + "serde_derive", + "serde_json", + "solana-account-decoder-client-types", + "solana-clock", + "solana-pubkey", + "solana-rpc-client-api", + "solana-signature", + "thiserror 2.0.11", + "tokio", + "tokio-stream", + "tokio-tungstenite 0.20.1", + "tungstenite 0.20.1", + "url", +] + +[[package]] +name = "solana-quic-client" +version = "2.2.0" +source = "git+https://github.com/anza-xyz/agave.git?branch=v2.2#f5c162cbfcc03985f63c0603086194277124e88b" +dependencies = [ + "async-lock", + "async-trait", + "futures", + "itertools 0.12.1", + "lazy_static", + "log", + "quinn", + "quinn-proto", + "rustls 0.23.23", + "solana-connection-cache", + "solana-keypair", + "solana-measure", + "solana-metrics", + "solana-net-utils", + "solana-pubkey", + "solana-quic-definitions", + "solana-rpc-client-api", + "solana-signer", + "solana-streamer", + "solana-tls-utils", + "solana-transaction-error", + "thiserror 2.0.11", + "tokio", +] + +[[package]] +name = "solana-quic-definitions" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea8d8b557d01e61e3d73803e0a273ba3f13eb01fc9dd2a4cc54797a7f20c91f9" +dependencies = [ + "solana-keypair", +] + +[[package]] +name = "solana-rayon-threadlimit" +version = "2.2.0" +source = "git+https://github.com/anza-xyz/agave.git?branch=v2.2#f5c162cbfcc03985f63c0603086194277124e88b" +dependencies = [ + "lazy_static", + "num_cpus", +] + +[[package]] +name = "solana-rent" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9c0ba8a033fd38dc86270843243af7769fa0575ca61f56064aa87a825649540" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-sysvar-id", +] + +[[package]] +name = "solana-rent-collector" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c245faddc73cac99b6b65f7e5c638b5242be70ae71cbcb11189ec4a1e6051f3" +dependencies = [ + "serde", + "serde_derive", + "solana-account", + "solana-clock", + "solana-epoch-schedule", + "solana-genesis-config", + "solana-pubkey", + "solana-rent", + "solana-sdk-ids", +] + +[[package]] +name = "solana-rent-debits" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48def7a8a9c3ae777c9d4de16a35f29510e2c8a8dd688f0ed3e3d7217aaa9e9d" +dependencies = [ + "solana-pubkey", + "solana-reward-info", +] + +[[package]] +name = "solana-reserved-account-keys" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95206c1e7567f87fed3fb5442f7f28ca066a547b0afe25f603ef17d6ca90977e" +dependencies = [ + "lazy_static", + "solana-feature-set", + "solana-pubkey", + "solana-sdk-ids", +] + +[[package]] +name = "solana-reward-info" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69c1667d87015f7b673d7633bec1b3bdc53380ef78c2eecf6927767950d5624b" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "solana-rpc-client" +version = "2.2.0" +source = "git+https://github.com/anza-xyz/agave.git?branch=v2.2#f5c162cbfcc03985f63c0603086194277124e88b" +dependencies = [ + "async-trait", + "base64 0.22.1", + "bincode", + "bs58", + "indicatif", + "log", + "reqwest", + "reqwest-middleware", + "semver", + "serde", + "serde_derive", + "serde_json", + "solana-account", + "solana-account-decoder-client-types", + "solana-clock", + "solana-commitment-config", + "solana-epoch-info", + "solana-epoch-schedule", + "solana-feature-gate-interface", + "solana-hash", + "solana-instruction", + "solana-message", + "solana-pubkey", + "solana-rpc-client-api", + "solana-signature", + "solana-transaction", + "solana-transaction-error", + "solana-transaction-status-client-types", + "solana-version", + "tokio", +] + +[[package]] +name = "solana-rpc-client-api" +version = "2.2.0" +source = "git+https://github.com/anza-xyz/agave.git?branch=v2.2#f5c162cbfcc03985f63c0603086194277124e88b" +dependencies = [ + "anyhow", + "base64 0.22.1", + "bs58", + "jsonrpc-core", + "reqwest", + "reqwest-middleware", + "semver", + "serde", + "serde_derive", + "serde_json", + "solana-account", + "solana-account-decoder-client-types", + "solana-clock", + "solana-commitment-config", + "solana-fee-calculator", + "solana-inflation", + "solana-inline-spl", + "solana-pubkey", + "solana-signer", + "solana-transaction-error", + "solana-transaction-status-client-types", + "solana-version", + "thiserror 2.0.11", +] + +[[package]] +name = "solana-rpc-client-nonce-utils" +version = "2.2.0" +source = "git+https://github.com/anza-xyz/agave.git?branch=v2.2#f5c162cbfcc03985f63c0603086194277124e88b" +dependencies = [ + "solana-account", + "solana-commitment-config", + "solana-hash", + "solana-message", + "solana-nonce", + "solana-pubkey", + "solana-rpc-client", + "solana-sdk-ids", + "thiserror 2.0.11", +] + +[[package]] +name = "solana-sanitize" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b9c8488d45d48d98e2aca7cb61bc1fc7e3a7e14aac48efb88b0ddd08fb785ae" + +[[package]] +name = "solana-sdk" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7f31a3861541f053cb770049f9727f3e2eab18940c21e289d2db8bfc7082c41" +dependencies = [ + "bincode", + "bs58", + "getrandom 0.1.16", + "js-sys", + "serde", + "serde_json", + "solana-account", + "solana-bn254", + "solana-client-traits", + "solana-cluster-type", + "solana-commitment-config", + "solana-compute-budget-interface", + "solana-decode-error", + "solana-derivation-path", + "solana-ed25519-program", + "solana-epoch-info", + "solana-epoch-rewards-hasher", + "solana-feature-set", + "solana-fee-structure", + "solana-genesis-config", + "solana-hard-forks", + "solana-inflation", + "solana-instruction", + "solana-keypair", + "solana-message", + "solana-native-token", + "solana-nonce-account", + "solana-offchain-message", + "solana-packet", + "solana-poh-config", + "solana-precompile-error", + "solana-precompiles", + "solana-presigner", + "solana-program", + "solana-program-memory", + "solana-pubkey", + "solana-quic-definitions", + "solana-rent-collector", + "solana-rent-debits", + "solana-reserved-account-keys", + "solana-reward-info", + "solana-sanitize", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-secp256k1-program", + "solana-secp256k1-recover", + "solana-secp256r1-program", + "solana-seed-derivable", + "solana-seed-phrase", + "solana-serde", + "solana-serde-varint", + "solana-short-vec", + "solana-shred-version", + "solana-signature", + "solana-signer", + "solana-system-transaction", + "solana-time-utils", + "solana-transaction", + "solana-transaction-context", + "solana-transaction-error", + "solana-validator-exit", + "thiserror 2.0.11", + "wasm-bindgen", +] + +[[package]] +name = "solana-sdk-ids" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6776348ff4384ceb2bca7b04a22bec4710e2551f42e2bd84d14340892d4a43db" +dependencies = [ + "solana-pubkey", +] + +[[package]] +name = "solana-sdk-macro" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cedd8618f65460ede61644d863b8fa29059b7f4392ed2b6ac737d432b5fbe1f6" +dependencies = [ + "bs58", + "proc-macro2", + "quote", + "syn 2.0.98", +] + +[[package]] +name = "solana-secp256k1-program" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4163a54e579e2d50f5c38cde401d4efef2bbcacfb7e59dcfb6a7b82a0f02fb60" +dependencies = [ + "bincode", + "digest 0.10.7", + "libsecp256k1", + "serde", + "serde_derive", + "sha3", + "solana-feature-set", + "solana-instruction", + "solana-precompile-error", + "solana-sdk-ids", +] + +[[package]] +name = "solana-secp256k1-recover" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e68ffe614d1adfce894ed8c7877e40d43507a7254b1eb89cfbeb479b8d10b1c" +dependencies = [ + "borsh 1.5.5", + "libsecp256k1", + "solana-define-syscall", + "thiserror 2.0.11", +] + +[[package]] +name = "solana-secp256r1-program" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9190530ab9c16fe118837b2cd4905f64677bc536dd1193829ea39793448c667" +dependencies = [ + "bytemuck", + "openssl", + "solana-feature-set", + "solana-instruction", + "solana-precompile-error", + "solana-sdk-ids", +] + +[[package]] +name = "solana-seed-derivable" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622328288b94203f2318ff920cc0f9d22d2de381d3bbc709b227011de27a35e9" +dependencies = [ + "solana-derivation-path", +] + +[[package]] +name = "solana-seed-phrase" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "777a3e5f685064f7775acdf25af35d62089faa5dfe0d9825da2988a3fc6b321d" +dependencies = [ + "hmac 0.12.1", + "pbkdf2 0.11.0", + "sha2 0.10.8", +] + +[[package]] +name = "solana-serde" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "247317d6750e2b83dda5a26f7ee4ed8b0dec1713170abb45c2a45194384bf72b" +dependencies = [ + "serde", +] + +[[package]] +name = "solana-serde-varint" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2df892c94d1d120fe12aebb05130edba58bde445607ba872cd5c9ae4f348f516" +dependencies = [ + "serde", +] + +[[package]] +name = "solana-serialize-utils" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e47c29ddb0b6678f669304a0f74458931c4413f4f62d45a047a14d007f0dfd3" +dependencies = [ + "solana-instruction", + "solana-pubkey", + "solana-sanitize", +] + +[[package]] +name = "solana-sha256-hasher" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e628c2ac45e6896dfd1de1fa8891ad77b6b97209c0732631904e41798a529e3d" +dependencies = [ + "sha2 0.10.8", + "solana-define-syscall", + "solana-hash", +] + +[[package]] +name = "solana-short-vec" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e98f50b5f03b56077bfe3956287765b1cd2b220d6a8e3c0b5b6993011cea239" +dependencies = [ + "serde", +] + +[[package]] +name = "solana-shred-version" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd33639ce0640e11e5525c13661fc0e4ddde4c033fa8bd364e2ea039511944a" +dependencies = [ + "solana-hard-forks", + "solana-hash", + "solana-sha256-hasher", +] + +[[package]] +name = "solana-signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a549905698c91340f66e44926e774681abb7e4eecb4a85fe30a4a7a4ef9ba642" +dependencies = [ + "bs58", + "ed25519-dalek", + "rand 0.8.5", + "serde", + "serde-big-array", + "serde_derive", + "solana-sanitize", +] + +[[package]] +name = "solana-signer" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58b85384f5de9c78cc05bc14a93facddb3f35b6d4dd96b66b3d11267b2efc066" +dependencies = [ + "solana-pubkey", + "solana-signature", + "solana-transaction-error", +] + +[[package]] +name = "solana-slot-hashes" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f64dff66ac8e2ddcd8228678b7bc81b7a799cd23e010b34bf6b72887016f838e" +dependencies = [ + "serde", + "serde_derive", + "solana-hash", + "solana-sdk-ids", + "solana-sysvar-id", +] + +[[package]] +name = "solana-slot-history" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2568f681cb16ed4db3abfeb1e9ed1e47a0e3dbe0419a730c7bcfd68030747a8" +dependencies = [ + "bv", + "serde", + "serde_derive", + "solana-sdk-ids", + "solana-sysvar-id", +] + +[[package]] +name = "solana-stable-layout" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9647ffca7c9a4d9eee626851fdd1ee1439fcef33228c4c86c7a6f3332b2f9bb9" +dependencies = [ + "solana-instruction", + "solana-pubkey", +] + +[[package]] +name = "solana-stake-interface" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5269e89fde216b4d7e1d1739cf5303f8398a1ff372a81232abbee80e554a838c" +dependencies = [ + "borsh 0.10.4", + "borsh 1.5.5", + "num-traits", + "serde", + "serde_derive", + "solana-clock", + "solana-cpi", + "solana-decode-error", + "solana-instruction", + "solana-program-error", + "solana-pubkey", + "solana-system-interface", + "solana-sysvar-id", +] + +[[package]] +name = "solana-streamer" +version = "2.2.0" +source = "git+https://github.com/anza-xyz/agave.git?branch=v2.2#f5c162cbfcc03985f63c0603086194277124e88b" +dependencies = [ + "async-channel", + "bytes", + "crossbeam-channel", + "dashmap", + "futures", + "futures-util", + "governor", + "histogram", + "indexmap 2.7.1", + "itertools 0.12.1", + "libc", + "log", + "nix", + "pem", + "percentage", + "quinn", + "quinn-proto", + "rand 0.8.5", + "rustls 0.23.23", + "smallvec", + "socket2", + "solana-keypair", + "solana-measure", + "solana-metrics", + "solana-net-utils", + "solana-packet", + "solana-perf", + "solana-pubkey", + "solana-quic-definitions", + "solana-signature", + "solana-signer", + "solana-time-utils", + "solana-tls-utils", + "solana-transaction-error", + "solana-transaction-metrics-tracker", + "thiserror 2.0.11", + "tokio", + "tokio-util", + "x509-parser", +] + +[[package]] +name = "solana-system-interface" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94d7c18cb1a91c6be5f5a8ac9276a1d7c737e39a21beba9ea710ab4b9c63bc90" +dependencies = [ + "js-sys", + "num-traits", + "serde", + "serde_derive", + "solana-decode-error", + "solana-instruction", + "solana-pubkey", + "wasm-bindgen", +] + +[[package]] +name = "solana-system-transaction" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad50e7d25b91189edd0827ba51bdac9eba1163a6e4b2c32504b59222c2d187f7" +dependencies = [ + "solana-hash", + "solana-keypair", + "solana-message", + "solana-pubkey", + "solana-signer", + "solana-system-interface", + "solana-transaction", +] + +[[package]] +name = "solana-sysvar" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e68c122b502fd9c5a0584af938d62f2cbfbdd60f22d3ecf40d3c8a23da5e563c" +dependencies = [ + "base64 0.22.1", + "bincode", + "bytemuck", + "bytemuck_derive", + "lazy_static", + "serde", + "serde_derive", + "solana-account-info", + "solana-clock", + "solana-define-syscall", + "solana-epoch-rewards", + "solana-epoch-schedule", + "solana-fee-calculator", + "solana-hash", + "solana-instruction", + "solana-instructions-sysvar", + "solana-last-restart-slot", + "solana-program-entrypoint", + "solana-program-error", + "solana-program-memory", + "solana-pubkey", + "solana-rent", + "solana-sanitize", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-slot-hashes", + "solana-slot-history", + "solana-stake-interface", + "solana-sysvar-id", +] + +[[package]] +name = "solana-sysvar-id" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df06917586e1eff97754d610fe59972ff9cb181c8c6112a89b7ca68d88977a00" +dependencies = [ + "solana-pubkey", + "solana-sdk-ids", +] + +[[package]] +name = "solana-thin-client" +version = "2.2.0" +source = "git+https://github.com/anza-xyz/agave.git?branch=v2.2#f5c162cbfcc03985f63c0603086194277124e88b" +dependencies = [ + "bincode", + "log", + "rayon", + "solana-account", + "solana-client-traits", + "solana-clock", + "solana-commitment-config", + "solana-connection-cache", + "solana-epoch-info", + "solana-hash", + "solana-instruction", + "solana-keypair", + "solana-message", + "solana-pubkey", + "solana-rpc-client", + "solana-rpc-client-api", + "solana-signature", + "solana-signer", + "solana-system-interface", + "solana-transaction", + "solana-transaction-error", +] + +[[package]] +name = "solana-time-utils" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1da442f9f36c711d49d1f5059da8c55b8a9bed03d26396646e82932a06fb53a" + +[[package]] +name = "solana-tls-utils" +version = "2.2.0" +source = "git+https://github.com/anza-xyz/agave.git?branch=v2.2#f5c162cbfcc03985f63c0603086194277124e88b" +dependencies = [ + "rustls 0.23.23", + "solana-keypair", + "solana-pubkey", + "solana-signer", + "x509-parser", +] + +[[package]] +name = "solana-tpu-client" +version = "2.2.0" +source = "git+https://github.com/anza-xyz/agave.git?branch=v2.2#f5c162cbfcc03985f63c0603086194277124e88b" +dependencies = [ + "async-trait", + "bincode", + "futures-util", + "indexmap 2.7.1", + "indicatif", + "log", + "rayon", + "solana-client-traits", + "solana-clock", + "solana-commitment-config", + "solana-connection-cache", + "solana-epoch-info", + "solana-measure", + "solana-message", + "solana-net-utils", + "solana-pubkey", + "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.11", + "tokio", +] + +[[package]] +name = "solana-transaction" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "075b7c2b50c1ce9a1d81802d39673d0b039f5dc5d2a018dfc07ae60b7f81f988" +dependencies = [ + "bincode", + "serde", + "serde_derive", + "solana-bincode", + "solana-feature-set", + "solana-hash", + "solana-instruction", + "solana-keypair", + "solana-message", + "solana-precompiles", + "solana-pubkey", + "solana-reserved-account-keys", + "solana-sanitize", + "solana-sdk-ids", + "solana-short-vec", + "solana-signature", + "solana-signer", + "solana-system-interface", + "solana-transaction-error", + "wasm-bindgen", +] + +[[package]] +name = "solana-transaction-context" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "717bb0e0ccfd2d16c63cc5270ee75e67e6741de7d4123494165e225c59d9d187" +dependencies = [ + "bincode", + "serde", + "serde_derive", + "solana-account", + "solana-instruction", + "solana-pubkey", + "solana-rent", + "solana-signature", +] + +[[package]] +name = "solana-transaction-error" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74cd8bc1bb3886d9565856d29db7d8be79a106f75c82da5c906ba8312e14298c" +dependencies = [ + "serde", + "serde_derive", + "solana-instruction", + "solana-sanitize", +] + +[[package]] +name = "solana-transaction-metrics-tracker" +version = "2.2.0" +source = "git+https://github.com/anza-xyz/agave.git?branch=v2.2#f5c162cbfcc03985f63c0603086194277124e88b" +dependencies = [ + "base64 0.22.1", + "bincode", + "lazy_static", + "log", + "rand 0.8.5", + "solana-packet", + "solana-perf", + "solana-short-vec", + "solana-signature", +] + +[[package]] +name = "solana-transaction-status-client-types" +version = "2.2.0" +source = "git+https://github.com/anza-xyz/agave.git?branch=v2.2#f5c162cbfcc03985f63c0603086194277124e88b" +dependencies = [ + "base64 0.22.1", + "bincode", + "bs58", + "serde", + "serde_derive", + "serde_json", + "solana-account-decoder-client-types", + "solana-commitment-config", + "solana-message", + "solana-reward-info", + "solana-signature", + "solana-transaction", + "solana-transaction-context", + "solana-transaction-error", + "thiserror 2.0.11", +] + +[[package]] +name = "solana-udp-client" +version = "2.2.0" +source = "git+https://github.com/anza-xyz/agave.git?branch=v2.2#f5c162cbfcc03985f63c0603086194277124e88b" +dependencies = [ + "async-trait", + "solana-connection-cache", + "solana-keypair", + "solana-net-utils", + "solana-streamer", + "solana-transaction-error", + "thiserror 2.0.11", + "tokio", +] + +[[package]] +name = "solana-validator-exit" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d61992deaa06427057f910ca9a591f386e7b3a34465a3cae8be98e55b26ba8f" + +[[package]] +name = "solana-version" +version = "2.2.0" +source = "git+https://github.com/anza-xyz/agave.git?branch=v2.2#f5c162cbfcc03985f63c0603086194277124e88b" +dependencies = [ + "semver", + "serde", + "serde_derive", + "solana-feature-set", + "solana-sanitize", + "solana-serde-varint", +] + +[[package]] +name = "solana-vote-interface" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fe6036f3a0748d039404998090915273b11379034656a132dd41cceb05abf94" +dependencies = [ + "bincode", + "num-derive", + "num-traits", + "serde", + "serde_derive", + "solana-clock", + "solana-decode-error", + "solana-hash", + "solana-instruction", + "solana-pubkey", + "solana-rent", + "solana-sdk-ids", + "solana-serde-varint", + "solana-serialize-utils", + "solana-short-vec", + "solana-system-interface", +] + +[[package]] +name = "solana-zk-token-sdk" +version = "2.2.0" +source = "git+https://github.com/anza-xyz/agave.git?branch=v2.2#f5c162cbfcc03985f63c0603086194277124e88b" +dependencies = [ + "aes-gcm-siv", + "base64 0.22.1", + "bincode", + "bytemuck", + "bytemuck_derive", + "curve25519-dalek 4.1.3", + "itertools 0.12.1", + "lazy_static", + "merlin", + "num-derive", + "num-traits", + "rand 0.8.5", + "serde", + "serde_derive", + "serde_json", + "sha3", + "solana-curve25519", + "solana-derivation-path", + "solana-instruction", + "solana-pubkey", + "solana-sdk-ids", + "solana-seed-derivable", + "solana-seed-phrase", + "solana-signature", + "solana-signer", + "subtle", + "thiserror 2.0.11", + "zeroize", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + +[[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 = "sqlx" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4410e73b3c0d8442c5f99b425d7a435b5ee0ae4167b3196771dd3f7a01be745f" +dependencies = [ + "sqlx-core", + "sqlx-macros", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", +] + +[[package]] +name = "sqlx-core" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a007b6936676aa9ab40207cde35daab0a04b823be8ae004368c0793b96a61e0" +dependencies = [ + "bytes", + "crc", + "crossbeam-queue", + "either", + "event-listener 5.4.0", + "futures-core", + "futures-intrusive", + "futures-io", + "futures-util", + "hashbrown 0.15.2", + "hashlink", + "indexmap 2.7.1", + "log", + "memchr", + "once_cell", + "percent-encoding", + "serde", + "serde_json", + "sha2 0.10.8", + "smallvec", + "thiserror 2.0.11", + "tokio", + "tokio-stream", + "tracing", + "url", +] + +[[package]] +name = "sqlx-macros" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3112e2ad78643fef903618d78cf0aec1cb3134b019730edb039b69eaf531f310" +dependencies = [ + "proc-macro2", + "quote", + "sqlx-core", + "sqlx-macros-core", + "syn 2.0.98", +] + +[[package]] +name = "sqlx-macros-core" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e9f90acc5ab146a99bf5061a7eb4976b573f560bc898ef3bf8435448dd5e7ad" +dependencies = [ + "dotenvy", + "either", + "heck 0.5.0", + "hex", + "once_cell", + "proc-macro2", + "quote", + "serde", + "serde_json", + "sha2 0.10.8", + "sqlx-core", + "sqlx-mysql", + "sqlx-postgres", + "sqlx-sqlite", + "syn 2.0.98", + "tempfile", + "tokio", + "url", +] + +[[package]] +name = "sqlx-mysql" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4560278f0e00ce64938540546f59f590d60beee33fffbd3b9cd47851e5fff233" +dependencies = [ + "atoi", + "base64 0.22.1", + "bitflags 2.8.0", + "byteorder", + "bytes", + "crc", + "digest 0.10.7", + "dotenvy", + "either", + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "generic-array", + "hex", + "hkdf", + "hmac 0.12.1", + "itoa", + "log", + "md-5", + "memchr", + "once_cell", + "percent-encoding", + "rand 0.8.5", + "rsa", + "serde", + "sha1", + "sha2 0.10.8", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror 2.0.11", + "tracing", + "whoami", +] + +[[package]] +name = "sqlx-postgres" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5b98a57f363ed6764d5b3a12bfedf62f07aa16e1856a7ddc2a0bb190a959613" +dependencies = [ + "atoi", + "base64 0.22.1", + "bitflags 2.8.0", + "byteorder", + "crc", + "dotenvy", + "etcetera", + "futures-channel", + "futures-core", + "futures-util", + "hex", + "hkdf", + "hmac 0.12.1", + "home", + "itoa", + "log", + "md-5", + "memchr", + "once_cell", + "rand 0.8.5", + "serde", + "serde_json", + "sha2 0.10.8", + "smallvec", + "sqlx-core", + "stringprep", + "thiserror 2.0.11", + "tracing", + "whoami", +] + +[[package]] +name = "sqlx-sqlite" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f85ca71d3a5b24e64e1d08dd8fe36c6c95c339a896cc33068148906784620540" +dependencies = [ + "atoi", + "flume", + "futures-channel", + "futures-core", + "futures-executor", + "futures-intrusive", + "futures-util", + "libsqlite3-sys", + "log", + "percent-encoding", + "serde", + "serde_urlencoded", + "sqlx-core", + "tracing", + "url", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "stringprep" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" +dependencies = [ + "unicode-bidi", + "unicode-normalization", + "unicode-properties", +] + +[[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.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1" +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 = "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.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", +] + +[[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 = "task-local-extensions" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba323866e5d033818e3240feeb9f7db2c4296674e4d9e16b97b7bf8f490434e8" +dependencies = [ + "pin-utils", +] + +[[package]] +name = "tempfile" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38c246215d7d24f48ae091a2902398798e05d978b24315d6efbc00ede9a8bb91" +dependencies = [ + "cfg-if", + "fastrand", + "getrandom 0.3.1", + "once_cell", + "rustix", + "windows-sys 0.59.0", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[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.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc" +dependencies = [ + "thiserror-impl 2.0.11", +] + +[[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.98", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", +] + +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "time" +version = "0.3.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tinystr" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tinyvec" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "022db8904dfa342efe721985167e9fcd16c29b226db4397ed752a761cfce81e8" +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.43.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d61fa4ffa3de412bfea335c6ecff681de2b609ba3c77ef3e00e521813a9ed9e" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.52.0", +] + +[[package]] +name = "tokio-macros" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", +] + +[[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.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37" +dependencies = [ + "rustls 0.23.23", + "tokio", +] + +[[package]] +name = "tokio-socks" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d4770b8024672c1101b3f6733eab95b18007dbe0847a8afe341fcf79e06043f" +dependencies = [ + "either", + "futures-util", + "thiserror 1.0.69", + "tokio", +] + +[[package]] +name = "tokio-stream" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" +dependencies = [ + "futures-util", + "log", + "rustls 0.21.12", + "tokio", + "tokio-rustls 0.24.1", + "tungstenite 0.20.1", + "webpki-roots 0.25.4", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edc5f74e248dc973e0dbb7b74c7e0d6fcc301c694ff50049504004ef4d0cdcd9" +dependencies = [ + "futures-util", + "log", + "rustls 0.23.23", + "rustls-pki-types", + "tokio", + "tokio-rustls 0.26.1", + "tungstenite 0.24.0", + "webpki-roots 0.26.8", +] + +[[package]] +name = "tokio-util" +version = "0.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" + +[[package]] +name = "toml_edit" +version = "0.22.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" +dependencies = [ + "indexmap 2.7.1", + "toml_datetime", + "winnow", +] + +[[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.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", +] + +[[package]] +name = "tracing-core" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + +[[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.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" +dependencies = [ + "byteorder", + "bytes", + "data-encoding", + "http 0.2.12", + "httparse", + "log", + "rand 0.8.5", + "rustls 0.21.12", + "sha1", + "thiserror 1.0.69", + "url", + "utf-8", + "webpki-roots 0.24.0", +] + +[[package]] +name = "tungstenite" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18e5b8366ee7a95b16d32197d0b2604b43a0be89dc5fac9f8e96ccafbaedda8a" +dependencies = [ + "byteorder", + "bytes", + "data-encoding", + "http 1.2.0", + "httparse", + "log", + "rand 0.8.5", + "rustls 0.23.23", + "rustls-pki-types", + "sha1", + "thiserror 1.0.69", + "utf-8", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicase" +version = "2.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" + +[[package]] +name = "unicode-bidi" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" + +[[package]] +name = "unicode-ident" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-properties" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" + +[[package]] +name = "unicode-width" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[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 = "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.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[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.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasi" +version = "0.13.3+wasi-0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" +dependencies = [ + "wit-bindgen-rt", +] + +[[package]] +name = "wasite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" + +[[package]] +name = "wasm-bindgen" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn 2.0.98", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" +dependencies = [ + "cfg-if", + "js-sys", + "once_cell", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +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 = "0.26.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09aed61f5e8d2c18344b3faa33a4c837855fe56642757754775548fee21386c4" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "webpki-roots" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b291546d5d9d1eab74f069c77749f2cb8504a12caa20f0f2de93ddbf6f411888" +dependencies = [ + "rustls-webpki 0.101.7", +] + +[[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.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2210b291f7ea53617fbafcc4939f10914214ec15aace5ba62293a668f322c5c9" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "whoami" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "372d5b87f58ec45c384ba03563b03544dc5fadc3983e434b286913f5b4a9bb6d" +dependencies = [ + "redox_syscall", + "wasite", +] + +[[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.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.6", +] + +[[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-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", + "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_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_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_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_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[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_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_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_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 = "winnow" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59690dea168f2198d1a3b0cac23b8063efcd11012f10ae4698f284808c8ef603" +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-rt" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" +dependencies = [ + "bitflags 2.8.0", +] + +[[package]] +name = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + +[[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.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", + "synstructure 0.13.1", +] + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", +] + +[[package]] +name = "zerofrom" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", + "synstructure 0.13.1", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", +] + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.98", +] + +[[package]] +name = "zstd" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54a3ab4db68cea366acc5c897c7b4d4d1b8994a9cd6e6f841f8964566a419059" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.13+zstd.1.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/dephy-vending_machine-examples/Cargo.toml b/dephy-vending_machine-examples/Cargo.toml new file mode 100644 index 0000000..b440d8f --- /dev/null +++ b/dephy-vending_machine-examples/Cargo.toml @@ -0,0 +1,36 @@ +[workspace] +resolver = "2" +members = [ + "balance-payment-sdk", + "examples/*", +] + +[workspace.package] +license = "MIT" + +[workspace.dependencies] +solana-client = { version = "2.2.0", git = "https://github.com/anza-xyz/agave.git", branch = "v2.2" } +solana-program = "2.2.0" +solana-sdk = { version = "2.2.0", features = ["openssl-vendored"] } +solana-zk-token-sdk = { version = "2.2.0", git = "https://github.com/anza-xyz/agave.git", branch = "v2.2" } + +arrayref = "0.3.9" +borsh = "0.10.4" +curve25519-dalek = "4.1.3" +num-derive = "0.4.2" +num-traits = "0.2.19" +serde = "1.0.217" +serde_json = "1.0.137" +serde_with = "3.12.0" +sha2 = "0.10.8" +thiserror = "2.0.11" +tracing = "0.1.41" + +clap = "4.5.29" +futures = "0.3.31" +nostr = "0.38.0" +nostr-sdk = "0.38.0" +tokio = "1.43.0" +tracing-subscriber = "0.3.19" + +dephy-balance-payment-sdk = { version = "0.1.0", path = "./balance-payment-sdk" } diff --git a/dephy-vending_machine-examples/MIT-LICENSE b/dephy-vending_machine-examples/MIT-LICENSE new file mode 100644 index 0000000..1784699 --- /dev/null +++ b/dephy-vending_machine-examples/MIT-LICENSE @@ -0,0 +1,20 @@ +Copyright (c) DEPHY TECHNOLOGY PTE. LTD. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/dephy-vending_machine-examples/README.md b/dephy-vending_machine-examples/README.md new file mode 100644 index 0000000..18278b1 --- /dev/null +++ b/dephy-vending_machine-examples/README.md @@ -0,0 +1,42 @@ +# DePHY vending machine examples + +This is a vending machine showcase for DePHY Messaging Layer. + +## Online demo + +The program has deployed to Solana devnet, address: `GguVKxU88NUe3GLtns7Uaa6a8Pjb9USKq3WD1rjZnPS9` + +See for the dApp + +## How it works + +![](./doc/architecture.png) + +## Repo contents + +- [Solana program and dApp](./balance-payment) + - [dApp](./balance-payment/app) +- [Pre-generated program Rust SDK](./balance-payment-sdk) +- Examples + - [DeCharge](./examples/decharge-controller) + - [Gacha](./examples/gacha-controller) + +## Run from source + +1. Run DePHY vending machine workers by: `docker compose up` +2. [Deploy the Solana program and run the dApp](./balance-payment/README.md) + +## TODO + +- Build a scripts to quick deploy a local demo +- Rename DeCharge things to vending machine +- Rich docs + +## Future works + +- Use an offchain account book to ensure the process transactionality +- Indexer and a dashboard dAPP for showing order history + +## License + +MIT diff --git a/dephy-vending_machine-examples/balance-payment-sdk/Cargo.lock b/dephy-vending_machine-examples/balance-payment-sdk/Cargo.lock new file mode 100644 index 0000000..a4de112 --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment-sdk/Cargo.lock @@ -0,0 +1,5616 @@ +# 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 = "addr2line" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + +[[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 = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "getrandom 0.2.15", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "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 = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[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 = "anyhow" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-std" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand 0.8.5", +] + +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[package]] +name = "arrayvec" +version = "0.7.6" +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-channel" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" +dependencies = [ + "concurrent-queue", + "event-listener 2.5.3", + "futures-core", +] + +[[package]] +name = "async-compression" +version = "0.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df895a515f70646414f4b45c0b79082783b80552b373a68283012928df56f522" +dependencies = [ + "brotli", + "flate2", + "futures-core", + "memchr", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "async-lock" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" +dependencies = [ + "event-listener 5.4.0", + "event-listener-strategy", + "pin-project-lite", +] + +[[package]] +name = "async-trait" +version = "0.1.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f934833b4b7233644e5848f235df3f57ed8c80f1528a26c3dfa13d2147fa056" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "backtrace" +version = "0.3.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-targets 0.52.6", +] + +[[package]] +name = "balance-payment-sdk" +version = "0.1.0" +dependencies = [ + "arrayref", + "borsh 0.10.4", + "curve25519-dalek 4.1.3", + "num-derive", + "num-traits", + "serde", + "serde_json", + "serde_with", + "sha2 0.10.8", + "solana-client", + "solana-program", + "solana-sdk", + "solana-zk-token-sdk", + "thiserror 2.0.11", + "tracing", +] + +[[package]] +name = "base64" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" + +[[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 = "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.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" +dependencies = [ + "serde", +] + +[[package]] +name = "blake3" +version = "1.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8ee0c1824c4dea5b5f81736aff91bae041d2c07ee1192bec91054e10e3e601e" +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 = [ + "generic-array", +] + +[[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 = "borsh" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115e54d64eb62cdebad391c19efc9dce4981c690c85a33a12199d99bb9546fee" +dependencies = [ + "borsh-derive 0.10.4", + "hashbrown 0.13.2", +] + +[[package]] +name = "borsh" +version = "1.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5430e3be710b68d984d1391c854eb431a9d548640711faa54eecb1df93db91cc" +dependencies = [ + "borsh-derive 1.5.5", + "cfg_aliases", +] + +[[package]] +name = "borsh-derive" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "831213f80d9423998dd696e2c5345aba6be7a0bd8cd19e31c5243e13df1cef89" +dependencies = [ + "borsh-derive-internal", + "borsh-schema-derive-internal", + "proc-macro-crate 0.1.5", + "proc-macro2", + "syn 1.0.109", +] + +[[package]] +name = "borsh-derive" +version = "1.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8b668d39970baad5356d7c83a86fee3a539e6f93bf6764c97368243e17a0487" +dependencies = [ + "once_cell", + "proc-macro-crate 3.2.0", + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[package]] +name = "borsh-derive-internal" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65d6ba50644c98714aa2a70d13d7df3cd75cd2b523a2b452bf010443800976b3" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "borsh-schema-derive-internal" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "276691d96f063427be83e6692b86148e488ebba9f48f77788724ca027ba3b6d4" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "brotli" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc97b8f16f944bba54f0433f07e30be199b6dc2bd25937444bbad560bcea29bd" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "4.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74fa05ad7d803d413eb8380983b092cbbaf9a85f151b871360e7b00cd7060b37" +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.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[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 = "bytemuck" +version = "1.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef657dfab802224e671f5818e9a4935f9b1957ed18e58292690cc39e7a4092a3" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fa76293b4f7bb636ab88fd78228235b5248b4d05cc589aed610f954af5d7c7a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" + +[[package]] +name = "caps" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "190baaad529bcfbde9e1a19022c42781bdb6ff9de25721abdb8fd98c0807730b" +dependencies = [ + "libc", + "thiserror 1.0.69", +] + +[[package]] +name = "cc" +version = "1.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13208fcbb66eaeffe09b99fffbe1af420f00a7b35aa99ad683dfc1aa76145229" +dependencies = [ + "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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[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.96", +] + +[[package]] +name = "chrono" +version = "0.4.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-targets 0.52.6", +] + +[[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 = "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 = "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.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea3c6ecd8059b57859df5c69830340ed3c41d30e3da0c1cbed90a96ac853041b" +dependencies = [ + "encode_unicode", + "libc", + "once_cell", + "unicode-width", + "windows-sys 0.59.0", +] + +[[package]] +name = "console_error_panic_hook" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if", + "wasm-bindgen", +] + +[[package]] +name = "console_log" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89f72f65e8501878b8a004d5a1afb780987e2ce2b4532c562e367a72c57499f" +dependencies = [ + "log", + "web-sys", +] + +[[package]] +name = "constant_time_eq" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "cpufeatures" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471" +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 = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "typenum", +] + +[[package]] +name = "crypto-mac" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" +dependencies = [ + "generic-array", + "subtle", +] + +[[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 = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" +dependencies = [ + "byteorder", + "digest 0.9.0", + "rand_core 0.5.1", + "subtle", + "zeroize", +] + +[[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 0.10.7", + "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.96", +] + +[[package]] +name = "darling" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.96", +] + +[[package]] +name = "darling_macro" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.96", +] + +[[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.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e60eed09d8c01d3cee5b7d30acb059b76614c918fa0f992e0dd6eeb10daad6f" + +[[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.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", + "serde", +] + +[[package]] +name = "derivation-path" +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 = "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", + "crypto-common", + "subtle", +] + +[[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.96", +] + +[[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.96", +] + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" +dependencies = [ + "signature", +] + +[[package]] +name = "ed25519-dalek" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" +dependencies = [ + "curve25519-dalek 3.2.0", + "ed25519", + "rand 0.7.3", + "serde", + "sha2 0.9.9", + "zeroize", +] + +[[package]] +name = "ed25519-dalek-bip32" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d2be62a4061b872c8c0873ee4fc6f101ce7b889d039f019c5fa2af471a59908" +dependencies = [ + "derivation-path", + "ed25519-dalek", + "hmac 0.12.1", + "sha2 0.10.8", +] + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[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.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1ab991c1362ac86c61ab6f556cff143daa22e5a15e4e189df818b2fd19fe65b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + +[[package]] +name = "event-listener" +version = "5.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3492acde4c3fc54c845eaab3eed8bd00c7a7d881f78bfc801e43a93dec1331ae" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3e4e0dd3673c1139bf041f3008816d9cf2946bbfac2945c09e523b8d7b05b2" +dependencies = [ + "event-listener 5.4.0", + "pin-project-lite", +] + +[[package]] +name = "feature-probe" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835a3dc7d1ec9e75e2b5fb4ba75396837112d2060b03f7d43bc1897c7f7211da" + +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + +[[package]] +name = "five8_const" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b4f62f0f8ca357f93ae90c8c2dd1041a1f665fde2f889ea9b1787903829015" +dependencies = [ + "five8_core", +] + +[[package]] +name = "five8_core" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94474d15a76982be62ca8a39570dccce148d98c238ebb7408b0a21b2c4bdddc4" + +[[package]] +name = "flate2" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c936bfdafb507ebbf50b8074c54fa31c5be9a1e7e5f467dd659697041407d07c" +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 = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "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.96", +] + +[[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 = [ + "serde", + "typenum", + "version_check", +] + +[[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.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "wasm-bindgen", +] + +[[package]] +name = "gimli" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" + +[[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 = "h2" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap 2.7.1", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "hash32" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" +dependencies = [ + "byteorder", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash", +] + +[[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" + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "histogram" +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 = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[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", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "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", + "hyper", + "rustls 0.21.12", + "tokio", + "tokio-rustls", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "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 = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[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.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + +[[package]] +name = "indexmap" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" +dependencies = [ + "equivalent", + "hashbrown 0.15.2", + "serde", +] + +[[package]] +name = "indicatif" +version = "0.17.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbf675b85ed934d3c67b5c5469701eec7db22689d0a2139d856e0925fa28b281" +dependencies = [ + "console", + "number_prefix", + "portable-atomic", + "unicode-width", + "web-time", +] + +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + +[[package]] +name = "ipnet" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" + +[[package]] +name = "jni" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6df18c2e3db7e453d3c6ac5b3e9d5182664d28788126d39b91f2d1e22b017ec" +dependencies = [ + "cesu8", + "combine 4.6.7", + "jni-sys", + "log", + "thiserror 1.0.69", + "walkdir", +] + +[[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.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +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 = "keccak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.169" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" + +[[package]] +name = "libsecp256k1" +version = "0.6.0" +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", +] + +[[package]] +name = "libsecp256k1-core" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0f6ab710cec28cef759c5f18671a27dae2a5f952cdaaee1d8e2908cb2478a80" +dependencies = [ + "crunchy", + "digest 0.9.0", + "subtle", +] + +[[package]] +name = "libsecp256k1-gen-ecmult" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccab96b584d38fac86a83f07e659f0deafd0253dc096dab5a36d53efe653c5c3" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "libsecp256k1-gen-genmult" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67abfe149395e3aa1c48a2beb32b068e2334402df8181f818d3aee2b304c4f5d" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "litemap" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" + +[[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" +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.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8402cab7aefae129c6977bb0ff1b8fd9a04eb5b51efc50a70bea51cda0c7924" +dependencies = [ + "adler2", +] + +[[package]] +name = "mio" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" +dependencies = [ + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.52.0", +] + +[[package]] +name = "nix" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +dependencies = [ + "bitflags 2.8.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.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[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.96", +] + +[[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.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "num_enum" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" +dependencies = [ + "proc-macro-crate 3.2.0", + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[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.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +dependencies = [ + "memchr", +] + +[[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.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" + +[[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.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" +dependencies = [ + "bitflags 2.8.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.96", +] + +[[package]] +name = "openssl-probe" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" + +[[package]] +name = "openssl-src" +version = "300.4.1+3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faa4eac4138c62414b5622d1b31c5c304f34b406b013c079c2bbc652fdd6678c" +dependencies = [ + "cc", +] + +[[package]] +name = "openssl-sys" +version = "0.9.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" +dependencies = [ + "cc", + "libc", + "openssl-src", + "pkg-config", + "vcpkg", +] + +[[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.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.52.6", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "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.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[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-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 = "pkg-config" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" + +[[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.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "280dc24453071f1b63954171985a0b0d30058d287960968b9b2aca264c8d4ee6" + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro-crate" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" +dependencies = [ + "toml", +] + +[[package]] +name = "proc-macro-crate" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro2" +version = "1.0.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" +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.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bd1fe6824cea6538803de3ff1bc0cf3949024db3d43c9643024bfb33a807c0e" +dependencies = [ + "crossbeam-utils", + "libc", + "once_cell", + "raw-cpuid", + "wasi 0.11.0+wasi-snapshot-preview1", + "web-sys", + "winapi", +] + +[[package]] +name = "quinn" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62e96808277ec6f97351a2380e6c25114bc9e67037775464979f3037c92d05ef" +dependencies = [ + "bytes", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls 0.23.21", + "socket2", + "thiserror 2.0.11", + "tokio", + "tracing", +] + +[[package]] +name = "quinn-proto" +version = "0.11.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2fe5ef3495d7d2e377ff17b1a8ce2ee2ec2a18cde8b6ad6619d65d0701c135d" +dependencies = [ + "bytes", + "getrandom 0.2.15", + "rand 0.8.5", + "ring", + "rustc-hash", + "rustls 0.23.21", + "rustls-pki-types", + "rustls-platform-verifier", + "slab", + "thiserror 2.0.11", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c40286217b4ba3a71d644d752e6a0b71f13f1b6a2c5311acfcbe0c2418ed904" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.59.0", +] + +[[package]] +name = "quote" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.7.3" +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", +] + +[[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_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", +] + +[[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_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.15", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "raw-cpuid" +version = "11.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6928fa44c097620b706542d428957635951bade7143269085389d42c8a4927e" +dependencies = [ + "bitflags 2.8.0", +] + +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "redox_syscall" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" +dependencies = [ + "bitflags 2.8.0", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "reqwest" +version = "0.11.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" +dependencies = [ + "async-compression", + "base64 0.21.7", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-rustls", + "ipnet", + "js-sys", + "log", + "mime", + "mime_guess", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls 0.21.12", + "rustls-pemfile 1.0.4", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "system-configuration", + "tokio", + "tokio-rustls", + "tokio-util", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots 0.25.4", + "winreg", +] + +[[package]] +name = "reqwest-middleware" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a735987236a8e238bf0296c7e351b999c188ccc11477f311b82b55c93984216" +dependencies = [ + "anyhow", + "async-trait", + "http", + "reqwest", + "serde", + "task-local-extensions", + "thiserror 1.0.69", +] + +[[package]] +name = "ring" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.15", + "libc", + "spin", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "rustc-hash" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497" + +[[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 = "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.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f287924602bf649d949c63dc8ac8b235fa5387d394020705b80c4eb597ce5b8" +dependencies = [ + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki 0.102.8", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-native-certs" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5" +dependencies = [ + "openssl-probe", + "rustls-pemfile 2.2.0", + "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-pemfile" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2bf47e6ff922db3825eb750c4e2ff784c6ff8fb9e13046ef6a1d1c5401b0b37" +dependencies = [ + "web-time", +] + +[[package]] +name = "rustls-platform-verifier" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4c7dc240fec5517e6c4eab3310438636cfe6391dfc345ba013109909a90d136" +dependencies = [ + "core-foundation", + "core-foundation-sys", + "jni", + "log", + "once_cell", + "rustls 0.23.21", + "rustls-native-certs", + "rustls-platform-verifier-android", + "rustls-webpki 0.102.8", + "security-framework", + "security-framework-sys", + "webpki-root-certs", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustls-platform-verifier-android" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" + +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "rustls-webpki" +version = "0.102.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[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.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +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" + +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "security-framework" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +dependencies = [ + "bitflags 2.8.0", + "core-foundation", + "core-foundation-sys", + "libc", + "num-bigint 0.4.6", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f79dfe2d285b0488816f30e700a7438c5a73d816b5b7d3ac72fbc48b0d185e03" + +[[package]] +name = "serde" +version = "1.0.217" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_bytes" +version = "0.11.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "387cc504cb06bb40a96c8e04e951fe01854cf6bc921053c954e4a606d9675c6a" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.217" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[package]] +name = "serde_json" +version = "1.0.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "930cfb6e6abf99298aaad7d29abbef7a9999a9a8806a40088f55f0dcec03146b" +dependencies = [ + "itoa", + "memchr", + "ryu", + "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.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6b6f7f2fcb69f747921f79f3926bd1e203fce4fef62c268dd3abfb6d86029aa" +dependencies = [ + "base64 0.22.1", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.7.1", + "serde", + "serde_derive", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d00caa5193a3c8362ac2b73be6b9e768aa5a4b2f721d8f4b339600c3cb51f8e" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +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", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest 0.10.7", + "keccak", +] + +[[package]] +name = "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.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +dependencies = [ + "libc", +] + +[[package]] +name = "signature" +version = "1.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" + +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "socket2" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "solana-account" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8557558040a6bf34101ea0ded1647bafc21c2a9ea0913034fa6794a304ba6791" +dependencies = [ + "bincode", + "serde", + "serde_bytes", + "serde_derive", + "solana-instruction", + "solana-program", +] + +[[package]] +name = "solana-account-decoder" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2353887223851d07071e790a6508d8df61032a5e01bb6f990d7abe7f58dde3aa" +dependencies = [ + "Inflector", + "base64 0.22.1", + "bincode", + "bs58", + "bv", + "lazy_static", + "serde", + "serde_derive", + "serde_json", + "solana-account-decoder-client-types", + "solana-config-program", + "solana-sdk", + "spl-token", + "spl-token-2022", + "spl-token-group-interface", + "spl-token-metadata-interface", + "thiserror 1.0.69", + "zstd", +] + +[[package]] +name = "solana-account-decoder-client-types" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435bb722c456f78dd3ac33a1b4641c46d5d41de5b072422ae5b0dc9f486c0928" +dependencies = [ + "base64 0.22.1", + "bs58", + "serde", + "serde_derive", + "serde_json", + "solana-account", + "solana-pubkey", + "zstd", +] + +[[package]] +name = "solana-account-info" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abeb32e8dbead1f920a919d8c781fe058cf657313aa237566fa812d2288f2aab" +dependencies = [ + "bincode", + "serde", + "solana-program-error", + "solana-program-memory", + "solana-pubkey", +] + +[[package]] +name = "solana-atomic-u64" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ceb7242711300b8d67933a3cd1c9b2cd7c4e98de529356ecddf340c98c457d" +dependencies = [ + "parking_lot", +] + +[[package]] +name = "solana-bincode" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e154567b6846f4721c713afdd14c56892800fb940793ef529a68d6db6cf1beef" +dependencies = [ + "bincode", + "serde", + "solana-instruction", +] + +[[package]] +name = "solana-bn254" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c42ad3282999ef7df859e7ed03a6e6a4187ff4931f9814ddcd0477dba2be15" +dependencies = [ + "ark-bn254", + "ark-ec", + "ark-ff", + "ark-serialize", + "bytemuck", + "solana-program", + "thiserror 1.0.69", +] + +[[package]] +name = "solana-borsh" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b2428671e99134c97990d2b466c33779f785376b7934e6bddb635929c54208f" +dependencies = [ + "borsh 0.10.4", + "borsh 1.5.5", +] + +[[package]] +name = "solana-client" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73d3a06371c4b63efa8d2dde9890b658891943807c529144eac6d2345538077d" +dependencies = [ + "async-trait", + "bincode", + "dashmap", + "futures", + "futures-util", + "indexmap 2.7.1", + "indicatif", + "log", + "quinn", + "rayon", + "solana-connection-cache", + "solana-measure", + "solana-pubsub-client", + "solana-quic-client", + "solana-rpc-client", + "solana-rpc-client-api", + "solana-rpc-client-nonce-utils", + "solana-sdk", + "solana-streamer", + "solana-thin-client", + "solana-tpu-client", + "solana-udp-client", + "thiserror 1.0.69", + "tokio", +] + +[[package]] +name = "solana-clock" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d639043cefcd061c31a342364adcb204406ebbd91ef86dfde88b74352b688cf" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-macro", + "solana-sysvar-id", +] + +[[package]] +name = "solana-compute-budget" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6c885192c0afe6f7beac13e1c8eb51ce36bc60e8f0b7631f9cbf72d8ca6aa03" +dependencies = [ + "solana-sdk", +] + +[[package]] +name = "solana-config-program" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "056ce3a28f5e22677e0db1fc976294041571c4d471a752bfc9f1b06f8828c488" +dependencies = [ + "bincode", + "chrono", + "serde", + "serde_derive", + "solana-log-collector", + "solana-program-runtime", + "solana-sdk", + "solana-short-vec", +] + +[[package]] +name = "solana-connection-cache" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52912ec1eb7b40af2a81269d0bb2cefba01f303383cba32067d0dc5020556e38" +dependencies = [ + "async-trait", + "bincode", + "crossbeam-channel", + "futures-util", + "indexmap 2.7.1", + "log", + "rand 0.8.5", + "rayon", + "solana-measure", + "solana-metrics", + "solana-sdk", + "thiserror 1.0.69", + "tokio", +] + +[[package]] +name = "solana-cpi" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b87b387931f41422be3d82190e29c8414bbb4e8517dd94afb838012260d7a60" +dependencies = [ + "solana-account-info", + "solana-define-syscall", + "solana-instruction", + "solana-program-error", + "solana-pubkey", + "solana-stable-layout", +] + +[[package]] +name = "solana-curve25519" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71b91a6c7db7874ab0721ba2ad49c34614c6af5bfa1a02f18ee471d28416b1fc" +dependencies = [ + "bytemuck", + "bytemuck_derive", + "curve25519-dalek 4.1.3", + "solana-program", + "thiserror 1.0.69", +] + +[[package]] +name = "solana-decode-error" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64b93163519c0b7419d3ac206207594d4b43e00267496996b898345ff3b31ed1" +dependencies = [ + "num-traits", +] + +[[package]] +name = "solana-define-syscall" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88d1b215d56d29f71782df6880d71b5a46cf9a4035046414488c7de6906899ba" + +[[package]] +name = "solana-derivation-path" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31edf5d285689b469471a1a0200f0c9196be7df155860bd83dfd735439172bd" +dependencies = [ + "derivation-path", + "qstring", + "uriparse", +] + +[[package]] +name = "solana-epoch-schedule" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88aa6588f178c32258eb616ef1428f2c86beae370d6486843313f6320e055190" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-macro", + "solana-sysvar-id", +] + +[[package]] +name = "solana-feature-set" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1736c5f6cb5d65e684a1daf425dd1479849e0793ffe877feedb602642ee5deb0" +dependencies = [ + "lazy_static", + "solana-clock", + "solana-epoch-schedule", + "solana-hash", + "solana-pubkey", + "solana-sha256-hasher", +] + +[[package]] +name = "solana-fee-calculator" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2ef28a47c3fcfd4ef8b19468531e32a431f6589f359cdbb927fc5e7fb859413" +dependencies = [ + "log", + "serde", + "serde_derive", +] + +[[package]] +name = "solana-hash" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad865143587f6173d0bd15ec66b749fd2682c865467ffd2bb725705e33f0c8fa" +dependencies = [ + "borsh 1.5.5", + "bs58", + "bytemuck", + "bytemuck_derive", + "js-sys", + "serde", + "serde_derive", + "solana-atomic-u64", + "solana-sanitize", + "wasm-bindgen", +] + +[[package]] +name = "solana-inflation" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a205cb59db7fa1afc89ad5d960ac5afb997ba231cdc943451811746c84b7776d" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "solana-inline-spl" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a47d825ad3f7d3eede036d2c3b11eb385912eb3e01872bc98901802f942eab8a" +dependencies = [ + "bytemuck", + "solana-pubkey", +] + +[[package]] +name = "solana-instruction" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af795f16bef3ae76e97978e35724ea88d2b9eba67a9e233adf48ccefeaa6e6b8" +dependencies = [ + "bincode", + "borsh 1.5.5", + "getrandom 0.2.15", + "js-sys", + "num-traits", + "serde", + "serde_derive", + "solana-define-syscall", + "solana-pubkey", + "wasm-bindgen", +] + +[[package]] +name = "solana-last-restart-slot" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f88c8171167f1fd4ef1e5a083fd0e8f35ac60aacd1ffe163a1ef7053a28524be" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-macro", + "solana-sysvar-id", +] + +[[package]] +name = "solana-log-collector" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7922b879e4c03e00bf6ed21b1f8579ac71f6743d95c22306bd1ba8994e4f90e8" +dependencies = [ + "log", +] + +[[package]] +name = "solana-measure" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13208871c6d000a0c7b7546ae605934f5eda3745f80f6926da1b6097c08f2de2" + +[[package]] +name = "solana-metrics" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "555986e126fe32ad94217c5d87c94f79b7f13abf96ef9d8de20dacbcf1c407e5" +dependencies = [ + "crossbeam-channel", + "gethostname", + "lazy_static", + "log", + "reqwest", + "solana-sdk", + "thiserror 1.0.69", +] + +[[package]] +name = "solana-msg" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aefec09cb47fb67b8f8c448e03491d4148c1749f27dcb74d1cfae6337695f94" +dependencies = [ + "solana-define-syscall", +] + +[[package]] +name = "solana-native-token" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81520eff9f776e62faa36a07250fcc467e54ca31ca9c87ab566a88b2f2691c05" + +[[package]] +name = "solana-net-utils" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b409b10fee2d0cbb2a721fa3ce7d7f6f32e0d3ae1f5807b1d6bc91d75970c72" +dependencies = [ + "bincode", + "crossbeam-channel", + "log", + "nix", + "rand 0.8.5", + "serde", + "serde_derive", + "socket2", + "solana-sdk", + "tokio", + "url", +] + +[[package]] +name = "solana-packet" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1f8c6e8a2cb0839ef49d8c6e34e89a5bc5ed97da855bf49528bae8c57eb39ed" +dependencies = [ + "bincode", + "bitflags 2.8.0", + "cfg_eval", + "serde", + "serde_derive", + "serde_with", +] + +[[package]] +name = "solana-perf" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fa10dd492bee710d0e231a3ff48c52d6e24f5339d97decaf1f0ddbde996f834" +dependencies = [ + "ahash", + "bincode", + "bv", + "caps", + "curve25519-dalek 4.1.3", + "dlopen2", + "fnv", + "lazy_static", + "libc", + "log", + "nix", + "rand 0.8.5", + "rayon", + "serde", + "solana-metrics", + "solana-rayon-threadlimit", + "solana-sdk", + "solana-short-vec", + "solana-vote-program", +] + +[[package]] +name = "solana-precompile-error" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83c01aefc15c451b4f573c1e4552f34ee8af53db285ee2f7ece17ef8b70d6c0a" +dependencies = [ + "num-traits", + "solana-decode-error", +] + +[[package]] +name = "solana-program" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d3a72c5eafd348bc5e5b731b40ad8dfde3023632e34e5ca9e52a655266ffae7" +dependencies = [ + "base64 0.22.1", + "bincode", + "bitflags 2.8.0", + "blake3", + "borsh 0.10.4", + "borsh 1.5.5", + "bs58", + "bv", + "bytemuck", + "bytemuck_derive", + "console_error_panic_hook", + "console_log", + "curve25519-dalek 4.1.3", + "five8_const", + "getrandom 0.2.15", + "js-sys", + "lazy_static", + "log", + "memoffset", + "num-bigint 0.4.6", + "num-derive", + "num-traits", + "parking_lot", + "rand 0.8.5", + "serde", + "serde_bytes", + "serde_derive", + "sha2 0.10.8", + "sha3", + "solana-account-info", + "solana-atomic-u64", + "solana-bincode", + "solana-borsh", + "solana-clock", + "solana-cpi", + "solana-decode-error", + "solana-define-syscall", + "solana-epoch-schedule", + "solana-fee-calculator", + "solana-hash", + "solana-instruction", + "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", + "solana-rent", + "solana-sanitize", + "solana-sdk-macro", + "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-id", + "solana-transaction-error", + "thiserror 1.0.69", + "wasm-bindgen", +] + +[[package]] +name = "solana-program-entrypoint" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "269ccabf1f3aff504a97aca0f8b72e6d3e1b7fb621cc18a2d21a28b17d52e112" +dependencies = [ + "solana-account-info", + "solana-msg", + "solana-program-error", + "solana-pubkey", +] + +[[package]] +name = "solana-program-error" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02f7a81eeb5c3d44b2953c46215af390ca2951a0b8069836ffbf3d368b012b35" +dependencies = [ + "borsh 1.5.5", + "num-traits", + "serde", + "serde_derive", + "solana-decode-error", + "solana-instruction", + "solana-msg", + "solana-pubkey", +] + +[[package]] +name = "solana-program-memory" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1debcdd14cee4dbc2761c1e267e8888188fb469956df0e2144cd6e2962c2532a" +dependencies = [ + "num-traits", + "solana-define-syscall", +] + +[[package]] +name = "solana-program-option" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b49ce216cce72eb0607610d2040b1979d999fe204f73ae2a669c2f4480d3c0" + +[[package]] +name = "solana-program-pack" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ff47a5dd9881187e85a45641405d9d1c57e9ebdc813e2ff74a1aa1f1ec9042" +dependencies = [ + "solana-program-error", +] + +[[package]] +name = "solana-program-runtime" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d4647f4dfed31aaa307d8c4924fec3fc981e88dd340eec45273afa84f3d01a4" +dependencies = [ + "base64 0.22.1", + "bincode", + "enum-iterator", + "itertools 0.12.1", + "libc", + "log", + "num-derive", + "num-traits", + "percentage", + "rand 0.8.5", + "serde", + "solana-compute-budget", + "solana-feature-set", + "solana-log-collector", + "solana-measure", + "solana-metrics", + "solana-sdk", + "solana-timings", + "solana-type-overrides", + "solana-vote", + "solana_rbpf", + "thiserror 1.0.69", +] + +[[package]] +name = "solana-pubkey" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02016ff5f98314c886e219c023bffba188ad8d70dec007247bd7a9da50423ac0" +dependencies = [ + "borsh 0.10.4", + "borsh 1.5.5", + "bs58", + "bytemuck", + "bytemuck_derive", + "curve25519-dalek 4.1.3", + "five8_const", + "getrandom 0.2.15", + "js-sys", + "num-traits", + "rand 0.8.5", + "serde", + "serde_derive", + "solana-atomic-u64", + "solana-decode-error", + "solana-define-syscall", + "solana-sanitize", + "solana-sha256-hasher", + "wasm-bindgen", +] + +[[package]] +name = "solana-pubsub-client" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af610bc169985b016e1f66bc9f0cc19559c9da5fb6ee0b8984ea69b1302e6619" +dependencies = [ + "crossbeam-channel", + "futures-util", + "log", + "reqwest", + "semver", + "serde", + "serde_derive", + "serde_json", + "solana-account-decoder", + "solana-rpc-client-api", + "solana-sdk", + "thiserror 1.0.69", + "tokio", + "tokio-stream", + "tokio-tungstenite", + "tungstenite", + "url", +] + +[[package]] +name = "solana-quic-client" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fa9aed25872d9af165499a9a2167d489ceb832d5e6eaa1aafa982286f62e06d" +dependencies = [ + "async-lock", + "async-trait", + "futures", + "itertools 0.12.1", + "lazy_static", + "log", + "quinn", + "quinn-proto", + "rustls 0.23.21", + "solana-connection-cache", + "solana-measure", + "solana-metrics", + "solana-net-utils", + "solana-rpc-client-api", + "solana-sdk", + "solana-streamer", + "thiserror 1.0.69", + "tokio", +] + +[[package]] +name = "solana-rayon-threadlimit" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d0ea6818ea3ae2067b18ba8f82577de19094d7abbb918ffb5cf5d7b0a6ffe88" +dependencies = [ + "lazy_static", + "num_cpus", +] + +[[package]] +name = "solana-rent" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "544fab48aacd3b9c740ef5206f30e8a44ef8bfe5676a9d7b1eed385265ec1265" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-macro", + "solana-sysvar-id", +] + +[[package]] +name = "solana-rpc-client" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ff2d4562f555ed4ca406d88483f2b8ad0248e41ea19721227ffb5c64529bff2" +dependencies = [ + "async-trait", + "base64 0.22.1", + "bincode", + "bs58", + "indicatif", + "log", + "reqwest", + "reqwest-middleware", + "semver", + "serde", + "serde_derive", + "serde_json", + "solana-account-decoder-client-types", + "solana-rpc-client-api", + "solana-sdk", + "solana-transaction-status-client-types", + "solana-version", + "solana-vote-program", + "tokio", +] + +[[package]] +name = "solana-rpc-client-api" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a50f6a180457400c9843980f1dd5db32b1153c295005ca85edb84bb7625acae" +dependencies = [ + "anyhow", + "base64 0.22.1", + "bs58", + "jsonrpc-core", + "reqwest", + "reqwest-middleware", + "semver", + "serde", + "serde_derive", + "serde_json", + "solana-account-decoder-client-types", + "solana-inline-spl", + "solana-sdk", + "solana-transaction-status-client-types", + "solana-version", + "thiserror 1.0.69", +] + +[[package]] +name = "solana-rpc-client-nonce-utils" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fa3be2840d3b8ebbdab96f62f59e0a9e6f9ba10f27b96a7d80d6897b15ff21a" +dependencies = [ + "solana-rpc-client", + "solana-sdk", + "thiserror 1.0.69", +] + +[[package]] +name = "solana-sanitize" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9677531dd4098d078515c66d69a04bfa0389d364a5c768561c719030b368a9db" + +[[package]] +name = "solana-sdk" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf93cfd5f5af23b59789eba96b6a6afd92a3a18a3fc6652259bfa1f32743caf4" +dependencies = [ + "bincode", + "bitflags 2.8.0", + "borsh 1.5.5", + "bs58", + "bytemuck", + "bytemuck_derive", + "byteorder", + "chrono", + "digest 0.10.7", + "ed25519-dalek", + "ed25519-dalek-bip32", + "getrandom 0.1.16", + "hmac 0.12.1", + "itertools 0.12.1", + "js-sys", + "lazy_static", + "libsecp256k1", + "log", + "memmap2", + "num-derive", + "num-traits", + "num_enum", + "pbkdf2", + "rand 0.7.3", + "rand 0.8.5", + "serde", + "serde_bytes", + "serde_derive", + "serde_json", + "serde_with", + "sha2 0.10.8", + "sha3", + "siphasher", + "solana-account", + "solana-bn254", + "solana-decode-error", + "solana-derivation-path", + "solana-feature-set", + "solana-inflation", + "solana-instruction", + "solana-native-token", + "solana-packet", + "solana-precompile-error", + "solana-program", + "solana-program-memory", + "solana-pubkey", + "solana-sanitize", + "solana-sdk-macro", + "solana-secp256k1-recover", + "solana-secp256r1-program", + "solana-serde-varint", + "solana-short-vec", + "solana-signature", + "solana-transaction-error", + "thiserror 1.0.69", + "wasm-bindgen", +] + +[[package]] +name = "solana-sdk-macro" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bded40f70accbe97030e5f7163017605e51a2631425229ec2b0a4339bd1163a" +dependencies = [ + "bs58", + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[package]] +name = "solana-secp256k1-recover" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee25b962814dec3c141e8182474046bae231f0521ed62c9bfdfb6722999ddc18" +dependencies = [ + "borsh 1.5.5", + "libsecp256k1", + "solana-define-syscall", + "thiserror 1.0.69", +] + +[[package]] +name = "solana-secp256r1-program" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ec53eff8861ab398b9ca4da7ef8c8da5d4170f8ea26557fc1581638b56326c1" +dependencies = [ + "bytemuck", + "openssl", + "solana-feature-set", + "solana-instruction", + "solana-precompile-error", + "solana-pubkey", +] + +[[package]] +name = "solana-security-txt" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "468aa43b7edb1f9b7b7b686d5c3aeb6630dc1708e86e31343499dd5c4d775183" + +[[package]] +name = "solana-serde-varint" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ff77c37cb995cc53ce1a4b78e5e9961957098677de6fdc6a4783ed37a8b0fcd" +dependencies = [ + "serde", +] + +[[package]] +name = "solana-serialize-utils" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57a10eb6e3177828145beaba85d352a4dbc47798fd95c5f86145e1a732684d6d" +dependencies = [ + "solana-instruction", + "solana-pubkey", + "solana-sanitize", +] + +[[package]] +name = "solana-sha256-hasher" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98c4229293979bf8bda7db2243ae75e13695341375577a4c44b07e4f0b7a5d9e" +dependencies = [ + "sha2 0.10.8", + "solana-define-syscall", + "solana-hash", +] + +[[package]] +name = "solana-short-vec" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc6a2a88d56e6771329970059bcab0fde9a719c8edae173fb26b2c08e427495a" +dependencies = [ + "serde", +] + +[[package]] +name = "solana-signature" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1e8a078879d8430cdfbee8e3c1cdf17da74c19d304662580fc463dc91e17699" +dependencies = [ + "bs58", + "ed25519-dalek", + "generic-array", + "rand 0.8.5", + "serde", + "serde_derive", + "solana-sanitize", +] + +[[package]] +name = "solana-slot-hashes" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88fa2a6e60f2d7016cf95429e0f60cf4a04d4eed167abd1a5f8b08cbda695893" +dependencies = [ + "serde", + "serde_derive", + "solana-hash", + "solana-sysvar-id", +] + +[[package]] +name = "solana-slot-history" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0fa66272c308c39a3ce1ca2a9c422de4bdedc28cfe706d6f2c68727bb626eb7" +dependencies = [ + "bv", + "serde", + "serde_derive", + "solana-sysvar-id", +] + +[[package]] +name = "solana-stable-layout" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2243571ebf8c0c9915c7e71b17469e173c6755fa58af8eb529db3dda84e3e19a" +dependencies = [ + "solana-instruction", + "solana-pubkey", +] + +[[package]] +name = "solana-streamer" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fddc2b38975c25199456ff46307c484affb459b84aedefe9618aece2a92326a9" +dependencies = [ + "async-channel", + "bytes", + "crossbeam-channel", + "dashmap", + "futures", + "futures-util", + "governor", + "histogram", + "indexmap 2.7.1", + "itertools 0.12.1", + "libc", + "log", + "nix", + "pem", + "percentage", + "quinn", + "quinn-proto", + "rand 0.8.5", + "rustls 0.23.21", + "smallvec", + "socket2", + "solana-measure", + "solana-metrics", + "solana-perf", + "solana-sdk", + "solana-transaction-metrics-tracker", + "thiserror 1.0.69", + "tokio", + "tokio-util", + "x509-parser", +] + +[[package]] +name = "solana-sysvar-id" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5822b63dd59f124e4920df8d87640a288bb40f4016fd275d028fee0b94a5a51e" +dependencies = [ + "solana-pubkey", +] + +[[package]] +name = "solana-thin-client" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1915dcb44dd5763a30aa32a687057e6a3b16781eb9f5db2800548990560272c3" +dependencies = [ + "bincode", + "log", + "rayon", + "solana-connection-cache", + "solana-rpc-client", + "solana-rpc-client-api", + "solana-sdk", +] + +[[package]] +name = "solana-timings" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "088c4507c8fd4f81c4039d78baf1ea7d68c8b80b2a973ba60838d33d2f7e752d" +dependencies = [ + "eager", + "enum-iterator", + "solana-sdk", +] + +[[package]] +name = "solana-tpu-client" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f944cd29eb540ca7e8df03c4e6043d5b8042eadab29b1848245c847a7c7c555" +dependencies = [ + "async-trait", + "bincode", + "futures-util", + "indexmap 2.7.1", + "indicatif", + "log", + "rayon", + "solana-connection-cache", + "solana-measure", + "solana-pubsub-client", + "solana-rpc-client", + "solana-rpc-client-api", + "solana-sdk", + "thiserror 1.0.69", + "tokio", +] + +[[package]] +name = "solana-transaction-error" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bd92caae17b4b828864b85cecf6dba6a87ad0ac433606b8bbd58334c74d0251" +dependencies = [ + "serde", + "serde_derive", + "solana-instruction", + "solana-sanitize", +] + +[[package]] +name = "solana-transaction-metrics-tracker" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "551dc5dad276919d24287e14e410759e93b801f2ca47dd9ad6c75eb49af26607" +dependencies = [ + "base64 0.22.1", + "bincode", + "lazy_static", + "log", + "rand 0.8.5", + "solana-perf", + "solana-sdk", + "solana-short-vec", +] + +[[package]] +name = "solana-transaction-status-client-types" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897c0015c246cb9b98cfaee15921c89cd7c1503bd368e9a3fd9336c17cd6be25" +dependencies = [ + "base64 0.22.1", + "bincode", + "bs58", + "serde", + "serde_derive", + "serde_json", + "solana-account-decoder-client-types", + "solana-sdk", + "solana-signature", + "thiserror 1.0.69", +] + +[[package]] +name = "solana-type-overrides" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f8e0b8916e7d78678428ca5d669950f6259ac332eab953ed0c8c2c88eebd3d2" +dependencies = [ + "lazy_static", + "rand 0.8.5", +] + +[[package]] +name = "solana-udp-client" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f5c6096b155fb1fb73d03fec2264a9671cbe208f71c4c32521ee9c979d91c75" +dependencies = [ + "async-trait", + "solana-connection-cache", + "solana-net-utils", + "solana-sdk", + "solana-streamer", + "thiserror 1.0.69", + "tokio", +] + +[[package]] +name = "solana-version" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae093290bf86006e323e883b9df845e4bdf84f23c37067cfa9837918ed04c87d" +dependencies = [ + "semver", + "serde", + "serde_derive", + "solana-feature-set", + "solana-sanitize", + "solana-serde-varint", +] + +[[package]] +name = "solana-vote" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8421891f95fe3b8291205e37043396c0fb26c2896cc94d53b153e1ba180992fa" +dependencies = [ + "itertools 0.12.1", + "log", + "serde", + "serde_derive", + "solana-sdk", + "thiserror 1.0.69", +] + +[[package]] +name = "solana-vote-program" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcf72a022dbb24dcfe1588aa09679042866eb7c0796ea479500ebe9355a7017f" +dependencies = [ + "bincode", + "log", + "num-derive", + "num-traits", + "serde", + "serde_derive", + "solana-feature-set", + "solana-metrics", + "solana-program", + "solana-program-runtime", + "solana-sdk", + "thiserror 1.0.69", +] + +[[package]] +name = "solana-zk-token-sdk" +version = "2.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b8cc94d7eddf6606c22504889b6528734db56ed3c2f651641453d13c9b233d7" +dependencies = [ + "aes-gcm-siv", + "base64 0.22.1", + "bincode", + "bytemuck", + "bytemuck_derive", + "byteorder", + "curve25519-dalek 4.1.3", + "itertools 0.12.1", + "lazy_static", + "merlin", + "num-derive", + "num-traits", + "rand 0.8.5", + "serde", + "serde_derive", + "serde_json", + "sha3", + "solana-curve25519", + "solana-derivation-path", + "solana-program", + "solana-sdk", + "subtle", + "thiserror 1.0.69", + "zeroize", +] + +[[package]] +name = "solana_rbpf" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c1941b5ef0c3ce8f2ac5dd984d0fb1a97423c4ff2a02eec81e3913f02e2ac2b" +dependencies = [ + "byteorder", + "combine 3.8.1", + "hash32", + "libc", + "log", + "rand 0.8.5", + "rustc-demangle", + "scroll", + "thiserror 1.0.69", + "winapi", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[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 = "spl-discriminator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a38ea8b6dedb7065887f12d62ed62c1743aa70749e8558f963609793f6fb12bc" +dependencies = [ + "bytemuck", + "solana-program", + "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.96", +] + +[[package]] +name = "spl-discriminator-syn" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c1f05593b7ca9eac7caca309720f2eafb96355e037e6d373b909a80fe7b69b9" +dependencies = [ + "proc-macro2", + "quote", + "sha2 0.10.8", + "syn 2.0.96", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-memo" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0dba2f2bb6419523405d21c301a32c9f9568354d4742552e7972af801f4bdb3" +dependencies = [ + "solana-program", +] + +[[package]] +name = "spl-pod" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c704c88fc457fa649ba3aabe195c79d885c3f26709efaddc453c8de352c90b87" +dependencies = [ + "borsh 1.5.5", + "bytemuck", + "bytemuck_derive", + "solana-program", + "solana-zk-token-sdk", + "spl-program-error", +] + +[[package]] +name = "spl-program-error" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7b28bed65356558133751cc32b48a7a5ddfc59ac4e941314630bbed1ac10532" +dependencies = [ + "num-derive", + "num-traits", + "solana-program", + "spl-program-error-derive", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-program-error-derive" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d375dd76c517836353e093c2dbb490938ff72821ab568b545fd30ab3256b3e" +dependencies = [ + "proc-macro2", + "quote", + "sha2 0.10.8", + "syn 2.0.96", +] + +[[package]] +name = "spl-tlv-account-resolution" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37a75a5f0fcc58126693ed78a17042e9dc53f07e357d6be91789f7d62aff61a4" +dependencies = [ + "bytemuck", + "solana-program", + "spl-discriminator", + "spl-pod", + "spl-program-error", + "spl-type-length-value", +] + +[[package]] +name = "spl-token" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70a0f06ac7f23dc0984931b1fe309468f14ea58e32660439c1cef19456f5d0e3" +dependencies = [ + "arrayref", + "bytemuck", + "num-derive", + "num-traits", + "num_enum", + "solana-program", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-token-2022" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c10f3483e48679619c76598d4e4aebb955bc49b0a5cc63323afbf44135c9bf" +dependencies = [ + "arrayref", + "bytemuck", + "num-derive", + "num-traits", + "num_enum", + "solana-program", + "solana-security-txt", + "solana-zk-token-sdk", + "spl-memo", + "spl-pod", + "spl-token", + "spl-token-group-interface", + "spl-token-metadata-interface", + "spl-transfer-hook-interface", + "spl-type-length-value", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-token-group-interface" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df8752b85a5ecc1d9f3a43bce3dd9a6a053673aacf5deb513d1cbb88d3534ffd" +dependencies = [ + "bytemuck", + "solana-program", + "spl-discriminator", + "spl-pod", + "spl-program-error", +] + +[[package]] +name = "spl-token-metadata-interface" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6c2318ddff97e006ed9b1291ebec0750a78547f870f62a69c56fe3b46a5d8fc" +dependencies = [ + "borsh 1.5.5", + "solana-program", + "spl-discriminator", + "spl-pod", + "spl-program-error", + "spl-type-length-value", +] + +[[package]] +name = "spl-transfer-hook-interface" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a110f33d941275d9f868b96daaa993f1e73b6806cc8836e43075b4d3ad8338a7" +dependencies = [ + "arrayref", + "bytemuck", + "solana-program", + "spl-discriminator", + "spl-pod", + "spl-program-error", + "spl-tlv-account-resolution", + "spl-type-length-value", +] + +[[package]] +name = "spl-type-length-value" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdcd73ec187bc409464c60759232e309f83b52a18a9c5610bf281c9c6432918c" +dependencies = [ + "bytemuck", + "solana-program", + "spl-discriminator", + "spl-pod", + "spl-program-error", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[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.96" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" +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 = "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.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[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 = "task-local-extensions" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba323866e5d033818e3240feeb9f7db2c4296674e4d9e16b97b7bf8f490434e8" +dependencies = [ + "pin-utils", +] + +[[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.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d452f284b73e6d76dd36758a0c8684b1d5be31f92b89d07fd5822175732206fc" +dependencies = [ + "thiserror-impl 2.0.11", +] + +[[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.96", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26afc1baea8a989337eeb52b6e72a039780ce45c3edfcc9c5b9d112feeb173c2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[package]] +name = "time" +version = "0.3.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tinystr" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tinyvec" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "022db8904dfa342efe721985167e9fcd16c29b226db4397ed752a761cfce81e8" +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.43.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d61fa4ffa3de412bfea335c6ecff681de2b609ba3c77ef3e00e521813a9ed9e" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.52.0", +] + +[[package]] +name = "tokio-macros" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[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-stream" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" +dependencies = [ + "futures-util", + "log", + "rustls 0.21.12", + "tokio", + "tokio-rustls", + "tungstenite", + "webpki-roots 0.25.4", +] + +[[package]] +name = "tokio-util" +version = "0.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" + +[[package]] +name = "toml_edit" +version = "0.22.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" +dependencies = [ + "indexmap 2.7.1", + "toml_datetime", + "winnow", +] + +[[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.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[package]] +name = "tracing-core" +version = "0.1.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" +dependencies = [ + "once_cell", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "tungstenite" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" +dependencies = [ + "byteorder", + "bytes", + "data-encoding", + "http", + "httparse", + "log", + "rand 0.8.5", + "rustls 0.21.12", + "sha1", + "thiserror 1.0.69", + "url", + "utf-8", + "webpki-roots 0.24.0", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicase" +version = "2.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" + +[[package]] +name = "unicode-ident" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" + +[[package]] +name = "unicode-width" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[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 = "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.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.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.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn 2.0.96", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" +dependencies = [ + "cfg-if", + "js-sys", + "once_cell", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +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 = "0.26.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cd5da49bdf1f30054cfe0b8ce2958b8fbeb67c4d82c8967a598af481bef255c" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "webpki-roots" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b291546d5d9d1eab74f069c77749f2cb8504a12caa20f0f2de93ddbf6f411888" +dependencies = [ + "rustls-webpki 0.101.7", +] + +[[package]] +name = "webpki-roots" +version = "0.25.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" + +[[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.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.6", +] + +[[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-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", + "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_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_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_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_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[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_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_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_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 = "winnow" +version = "0.6.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8d71a593cc5c42ad7876e2c1fda56f314f3754c084128833e64f1345ff8a03a" +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 = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + +[[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.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", + "synstructure 0.13.1", +] + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[package]] +name = "zerofrom" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", + "synstructure 0.13.1", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[package]] +name = "zstd" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54a3ab4db68cea366acc5c897c7b4d4d1b8994a9cd6e6f841f8964566a419059" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.13+zstd.1.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/dephy-vending_machine-examples/balance-payment-sdk/Cargo.toml b/dephy-vending_machine-examples/balance-payment-sdk/Cargo.toml new file mode 100644 index 0000000..aff6e3c --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment-sdk/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "dephy-balance-payment-sdk" +version = "0.1.0" +edition = "2021" +license.workspace = true + +[features] +default = ["serde"] +serde = ["dep:serde", "dep:serde_with"] + +[dependencies] +arrayref = { workspace = true } +borsh = { workspace = true } +curve25519-dalek = { workspace = true } +num-derive = { workspace = true } +num-traits = { workspace = true } +serde = { workspace = true, optional = true } +serde_json = { workspace = true } +serde_with = { workspace = true, optional = true } +sha2 = { workspace = true } +solana-client = { workspace = true } +solana-program = { workspace = true } +solana-sdk = { workspace = true } +solana-zk-token-sdk = { workspace = true } +thiserror = { workspace = true } +tracing = { workspace = true } diff --git a/dephy-vending_machine-examples/balance-payment-sdk/src/error.rs b/dephy-vending_machine-examples/balance-payment-sdk/src/error.rs new file mode 100644 index 0000000..78b612d --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment-sdk/src/error.rs @@ -0,0 +1,16 @@ +#[derive(Debug, thiserror::Error)] +#[non_exhaustive] +pub enum Error { + #[error("Io error: {0}")] + Io(#[from] std::io::Error), + #[error("Parse pubkey error: ")] + ParsePubkey(#[from] solana_program::pubkey::ParsePubkeyError), + #[error("Serde json error: {0}")] + SerdeJson(#[from] serde_json::Error), + #[error("Solana client error: {0}")] + SolanaClient(#[from] solana_client::client_error::ClientError), + #[error("Signature verification failed: {0}")] + SignatureVerificationFailed(String), + #[error("Keypair read failed: {0}")] + KeypairReadFailed(Box), +} diff --git a/dephy-vending_machine-examples/balance-payment-sdk/src/generated/accounts/global_account.rs b/dephy-vending_machine-examples/balance-payment-sdk/src/generated/accounts/global_account.rs new file mode 100644 index 0000000..ad25c9a --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment-sdk/src/generated/accounts/global_account.rs @@ -0,0 +1,77 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use borsh::BorshDeserialize; +use borsh::BorshSerialize; +use solana_program::pubkey::Pubkey; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct GlobalAccount { + pub discriminator: [u8; 8], + #[cfg_attr( + feature = "serde", + serde(with = "serde_with::As::") + )] + pub authority: Pubkey, + #[cfg_attr( + feature = "serde", + serde(with = "serde_with::As::") + )] + pub bot: Pubkey, + #[cfg_attr( + feature = "serde", + serde(with = "serde_with::As::") + )] + pub treasury: Pubkey, +} + +impl GlobalAccount { + pub const LEN: usize = 104; + + #[inline(always)] + pub fn from_bytes(data: &[u8]) -> Result { + let mut data = data; + Self::deserialize(&mut data) + } +} + +impl<'a> TryFrom<&solana_program::account_info::AccountInfo<'a>> for GlobalAccount { + type Error = std::io::Error; + + fn try_from( + account_info: &solana_program::account_info::AccountInfo<'a>, + ) -> Result { + let mut data: &[u8] = &(*account_info.data).borrow(); + Self::deserialize(&mut data) + } +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AccountDeserialize for GlobalAccount { + fn try_deserialize_unchecked(buf: &mut &[u8]) -> anchor_lang::Result { + Ok(Self::deserialize(buf)?) + } +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AccountSerialize for GlobalAccount {} + +#[cfg(feature = "anchor")] +impl anchor_lang::Owner for GlobalAccount { + fn owner() -> Pubkey { + crate::BALANCE_PAYMENT_ID + } +} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::IdlBuild for GlobalAccount {} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::Discriminator for GlobalAccount { + const DISCRIMINATOR: [u8; 8] = [0; 8]; +} diff --git a/dephy-vending_machine-examples/balance-payment-sdk/src/generated/accounts/lock_account.rs b/dephy-vending_machine-examples/balance-payment-sdk/src/generated/accounts/lock_account.rs new file mode 100644 index 0000000..07ca4c5 --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment-sdk/src/generated/accounts/lock_account.rs @@ -0,0 +1,62 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct LockAccount { + pub discriminator: [u8; 8], + pub amount: u64, +} + +impl LockAccount { + pub const LEN: usize = 16; + + #[inline(always)] + pub fn from_bytes(data: &[u8]) -> Result { + let mut data = data; + Self::deserialize(&mut data) + } +} + +impl<'a> TryFrom<&solana_program::account_info::AccountInfo<'a>> for LockAccount { + type Error = std::io::Error; + + fn try_from( + account_info: &solana_program::account_info::AccountInfo<'a>, + ) -> Result { + let mut data: &[u8] = &(*account_info.data).borrow(); + Self::deserialize(&mut data) + } +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AccountDeserialize for LockAccount { + fn try_deserialize_unchecked(buf: &mut &[u8]) -> anchor_lang::Result { + Ok(Self::deserialize(buf)?) + } +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AccountSerialize for LockAccount {} + +#[cfg(feature = "anchor")] +impl anchor_lang::Owner for LockAccount { + fn owner() -> Pubkey { + crate::BALANCE_PAYMENT_ID + } +} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::IdlBuild for LockAccount {} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::Discriminator for LockAccount { + const DISCRIMINATOR: [u8; 8] = [0; 8]; +} diff --git a/dephy-vending_machine-examples/balance-payment-sdk/src/generated/accounts/mod.rs b/dephy-vending_machine-examples/balance-payment-sdk/src/generated/accounts/mod.rs new file mode 100644 index 0000000..c609503 --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment-sdk/src/generated/accounts/mod.rs @@ -0,0 +1,14 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +pub(crate) mod r#global_account; +pub(crate) mod r#lock_account; +pub(crate) mod r#user_account; + +pub use self::r#global_account::*; +pub use self::r#lock_account::*; +pub use self::r#user_account::*; diff --git a/dephy-vending_machine-examples/balance-payment-sdk/src/generated/accounts/user_account.rs b/dephy-vending_machine-examples/balance-payment-sdk/src/generated/accounts/user_account.rs new file mode 100644 index 0000000..aee821a --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment-sdk/src/generated/accounts/user_account.rs @@ -0,0 +1,69 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use borsh::BorshDeserialize; +use borsh::BorshSerialize; +use solana_program::pubkey::Pubkey; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct UserAccount { + pub discriminator: [u8; 8], + pub nonce: u64, + pub locked_amount: u64, + #[cfg_attr( + feature = "serde", + serde(with = "serde_with::As::") + )] + pub vault: Pubkey, +} + +impl UserAccount { + pub const LEN: usize = 56; + + #[inline(always)] + pub fn from_bytes(data: &[u8]) -> Result { + let mut data = data; + Self::deserialize(&mut data) + } +} + +impl<'a> TryFrom<&solana_program::account_info::AccountInfo<'a>> for UserAccount { + type Error = std::io::Error; + + fn try_from( + account_info: &solana_program::account_info::AccountInfo<'a>, + ) -> Result { + let mut data: &[u8] = &(*account_info.data).borrow(); + Self::deserialize(&mut data) + } +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AccountDeserialize for UserAccount { + fn try_deserialize_unchecked(buf: &mut &[u8]) -> anchor_lang::Result { + Ok(Self::deserialize(buf)?) + } +} + +#[cfg(feature = "anchor")] +impl anchor_lang::AccountSerialize for UserAccount {} + +#[cfg(feature = "anchor")] +impl anchor_lang::Owner for UserAccount { + fn owner() -> Pubkey { + crate::BALANCE_PAYMENT_ID + } +} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::IdlBuild for UserAccount {} + +#[cfg(feature = "anchor-idl-build")] +impl anchor_lang::Discriminator for UserAccount { + const DISCRIMINATOR: [u8; 8] = [0; 8]; +} diff --git a/dephy-vending_machine-examples/balance-payment-sdk/src/generated/errors/balance_payment.rs b/dephy-vending_machine-examples/balance-payment-sdk/src/generated/errors/balance_payment.rs new file mode 100644 index 0000000..49eaf84 --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment-sdk/src/generated/errors/balance_payment.rs @@ -0,0 +1,43 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use num_derive::FromPrimitive; +use thiserror::Error; + +#[derive(Clone, Debug, Eq, Error, FromPrimitive, PartialEq)] +pub enum BalancePaymentError { + /// 6000 - Unauthorized access. + #[error("Unauthorized access.")] + Unauthorized = 0x1770, + /// 6001 - Insufficient funds. + #[error("Insufficient funds.")] + InsufficientFunds = 0x1771, + /// 6002 - The signature format or recovery ID is incorrect. + #[error("The signature format or recovery ID is incorrect.")] + SignatureFormatInvalid = 0x1772, + /// 6003 - Failed to recover public key from signature. + #[error("Failed to recover public key from signature.")] + SignatureRecoveryFailed = 0x1773, + /// 6004 - The recovered public key does not match the user's public key. + #[error("The recovered public key does not match the user's public key.")] + SignatureMismatch = 0x1774, + /// 6005 - The signature is expired. + #[error("The signature is expired.")] + SignatureExpired = 0x1775, +} + +impl solana_program::program_error::PrintProgramError for BalancePaymentError { + fn print(&self) { + solana_program::msg!(&self.to_string()); + } +} + +impl solana_program::decode_error::DecodeError for BalancePaymentError { + fn type_of() -> &'static str { + "BalancePaymentError" + } +} diff --git a/dephy-vending_machine-examples/balance-payment-sdk/src/generated/errors/mod.rs b/dephy-vending_machine-examples/balance-payment-sdk/src/generated/errors/mod.rs new file mode 100644 index 0000000..4fe38d1 --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment-sdk/src/generated/errors/mod.rs @@ -0,0 +1,10 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +pub(crate) mod balance_payment; + +pub use self::balance_payment::BalancePaymentError; diff --git a/dephy-vending_machine-examples/balance-payment-sdk/src/generated/instructions/deposit.rs b/dephy-vending_machine-examples/balance-payment-sdk/src/generated/instructions/deposit.rs new file mode 100644 index 0000000..3375c27 --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment-sdk/src/generated/instructions/deposit.rs @@ -0,0 +1,472 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +/// Accounts. +pub struct Deposit { + pub user_account: solana_program::pubkey::Pubkey, + + pub user: solana_program::pubkey::Pubkey, + + pub vault: solana_program::pubkey::Pubkey, + + pub payer: solana_program::pubkey::Pubkey, + + pub system_program: solana_program::pubkey::Pubkey, +} + +impl Deposit { + pub fn instruction( + &self, + args: DepositInstructionArgs, + ) -> solana_program::instruction::Instruction { + self.instruction_with_remaining_accounts(args, &[]) + } + #[allow(clippy::vec_init_then_push)] + pub fn instruction_with_remaining_accounts( + &self, + args: DepositInstructionArgs, + remaining_accounts: &[solana_program::instruction::AccountMeta], + ) -> solana_program::instruction::Instruction { + let mut accounts = Vec::with_capacity(5 + remaining_accounts.len()); + accounts.push(solana_program::instruction::AccountMeta::new( + self.user_account, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + self.user, true, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + self.vault, false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + self.payer, true, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + self.system_program, + false, + )); + accounts.extend_from_slice(remaining_accounts); + let mut data = DepositInstructionData::new().try_to_vec().unwrap(); + let mut args = args.try_to_vec().unwrap(); + data.append(&mut args); + + solana_program::instruction::Instruction { + program_id: crate::BALANCE_PAYMENT_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct DepositInstructionData { + discriminator: [u8; 8], +} + +impl DepositInstructionData { + pub fn new() -> Self { + Self { + discriminator: [242, 35, 198, 137, 82, 225, 242, 182], + } + } +} + +impl Default for DepositInstructionData { + fn default() -> Self { + Self::new() + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct DepositInstructionArgs { + pub amount: u64, +} + +/// Instruction builder for `Deposit`. +/// +/// ### Accounts: +/// +/// 0. `[writable]` user_account +/// 1. `[writable, signer]` user +/// 2. `[writable]` vault +/// 3. `[writable, signer]` payer +/// 4. `[optional]` system_program (default to `11111111111111111111111111111111`) +#[derive(Clone, Debug, Default)] +pub struct DepositBuilder { + user_account: Option, + user: Option, + vault: Option, + payer: Option, + system_program: Option, + amount: Option, + __remaining_accounts: Vec, +} + +impl DepositBuilder { + pub fn new() -> Self { + Self::default() + } + #[inline(always)] + pub fn user_account(&mut self, user_account: solana_program::pubkey::Pubkey) -> &mut Self { + self.user_account = Some(user_account); + self + } + #[inline(always)] + pub fn user(&mut self, user: solana_program::pubkey::Pubkey) -> &mut Self { + self.user = Some(user); + self + } + #[inline(always)] + pub fn vault(&mut self, vault: solana_program::pubkey::Pubkey) -> &mut Self { + self.vault = Some(vault); + self + } + #[inline(always)] + pub fn payer(&mut self, payer: solana_program::pubkey::Pubkey) -> &mut Self { + self.payer = Some(payer); + self + } + /// `[optional account, default to '11111111111111111111111111111111']` + #[inline(always)] + pub fn system_program(&mut self, system_program: solana_program::pubkey::Pubkey) -> &mut Self { + self.system_program = Some(system_program); + self + } + #[inline(always)] + pub fn amount(&mut self, amount: u64) -> &mut Self { + self.amount = Some(amount); + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: solana_program::instruction::AccountMeta, + ) -> &mut Self { + self.__remaining_accounts.push(account); + self + } + /// Add additional accounts to the instruction. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[solana_program::instruction::AccountMeta], + ) -> &mut Self { + self.__remaining_accounts.extend_from_slice(accounts); + self + } + #[allow(clippy::clone_on_copy)] + pub fn instruction(&self) -> solana_program::instruction::Instruction { + let accounts = Deposit { + user_account: self.user_account.expect("user_account is not set"), + user: self.user.expect("user is not set"), + vault: self.vault.expect("vault is not set"), + payer: self.payer.expect("payer is not set"), + system_program: self + .system_program + .unwrap_or(solana_program::pubkey!("11111111111111111111111111111111")), + }; + let args = DepositInstructionArgs { + amount: self.amount.clone().expect("amount is not set"), + }; + + accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) + } +} + +/// `deposit` CPI accounts. +pub struct DepositCpiAccounts<'a, 'b> { + pub user_account: &'b solana_program::account_info::AccountInfo<'a>, + + pub user: &'b solana_program::account_info::AccountInfo<'a>, + + pub vault: &'b solana_program::account_info::AccountInfo<'a>, + + pub payer: &'b solana_program::account_info::AccountInfo<'a>, + + pub system_program: &'b solana_program::account_info::AccountInfo<'a>, +} + +/// `deposit` CPI instruction. +pub struct DepositCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_program::account_info::AccountInfo<'a>, + + pub user_account: &'b solana_program::account_info::AccountInfo<'a>, + + pub user: &'b solana_program::account_info::AccountInfo<'a>, + + pub vault: &'b solana_program::account_info::AccountInfo<'a>, + + pub payer: &'b solana_program::account_info::AccountInfo<'a>, + + pub system_program: &'b solana_program::account_info::AccountInfo<'a>, + /// The arguments for the instruction. + pub __args: DepositInstructionArgs, +} + +impl<'a, 'b> DepositCpi<'a, 'b> { + pub fn new( + program: &'b solana_program::account_info::AccountInfo<'a>, + accounts: DepositCpiAccounts<'a, 'b>, + args: DepositInstructionArgs, + ) -> Self { + Self { + __program: program, + user_account: accounts.user_account, + user: accounts.user, + vault: accounts.vault, + payer: accounts.payer, + system_program: accounts.system_program, + __args: args, + } + } + #[inline(always)] + pub fn invoke(&self) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], &[]) + } + #[inline(always)] + pub fn invoke_with_remaining_accounts( + &self, + remaining_accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], remaining_accounts) + } + #[inline(always)] + pub fn invoke_signed( + &self, + signers_seeds: &[&[&[u8]]], + ) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(signers_seeds, &[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed_with_remaining_accounts( + &self, + signers_seeds: &[&[&[u8]]], + remaining_accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> solana_program::entrypoint::ProgramResult { + let mut accounts = Vec::with_capacity(5 + remaining_accounts.len()); + accounts.push(solana_program::instruction::AccountMeta::new( + *self.user_account.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + *self.user.key, + true, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + *self.vault.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + *self.payer.key, + true, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *self.system_program.key, + false, + )); + remaining_accounts.iter().for_each(|remaining_account| { + accounts.push(solana_program::instruction::AccountMeta { + pubkey: *remaining_account.0.key, + is_signer: remaining_account.1, + is_writable: remaining_account.2, + }) + }); + let mut data = DepositInstructionData::new().try_to_vec().unwrap(); + let mut args = self.__args.try_to_vec().unwrap(); + data.append(&mut args); + + let instruction = solana_program::instruction::Instruction { + program_id: crate::BALANCE_PAYMENT_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(6 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.user_account.clone()); + account_infos.push(self.user.clone()); + account_infos.push(self.vault.clone()); + account_infos.push(self.payer.clone()); + account_infos.push(self.system_program.clone()); + remaining_accounts + .iter() + .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); + + if signers_seeds.is_empty() { + solana_program::program::invoke(&instruction, &account_infos) + } else { + solana_program::program::invoke_signed(&instruction, &account_infos, signers_seeds) + } + } +} + +/// Instruction builder for `Deposit` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[writable]` user_account +/// 1. `[writable, signer]` user +/// 2. `[writable]` vault +/// 3. `[writable, signer]` payer +/// 4. `[]` system_program +#[derive(Clone, Debug)] +pub struct DepositCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> DepositCpiBuilder<'a, 'b> { + pub fn new(program: &'b solana_program::account_info::AccountInfo<'a>) -> Self { + let instruction = Box::new(DepositCpiBuilderInstruction { + __program: program, + user_account: None, + user: None, + vault: None, + payer: None, + system_program: None, + amount: None, + __remaining_accounts: Vec::new(), + }); + Self { instruction } + } + #[inline(always)] + pub fn user_account( + &mut self, + user_account: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.user_account = Some(user_account); + self + } + #[inline(always)] + pub fn user(&mut self, user: &'b solana_program::account_info::AccountInfo<'a>) -> &mut Self { + self.instruction.user = Some(user); + self + } + #[inline(always)] + pub fn vault(&mut self, vault: &'b solana_program::account_info::AccountInfo<'a>) -> &mut Self { + self.instruction.vault = Some(vault); + self + } + #[inline(always)] + pub fn payer(&mut self, payer: &'b solana_program::account_info::AccountInfo<'a>) -> &mut Self { + self.instruction.payer = Some(payer); + self + } + #[inline(always)] + pub fn system_program( + &mut self, + system_program: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.system_program = Some(system_program); + self + } + #[inline(always)] + pub fn amount(&mut self, amount: u64) -> &mut Self { + self.instruction.amount = Some(amount); + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: &'b solana_program::account_info::AccountInfo<'a>, + is_writable: bool, + is_signer: bool, + ) -> &mut Self { + self.instruction + .__remaining_accounts + .push((account, is_writable, is_signer)); + self + } + /// Add additional accounts to the instruction. + /// + /// Each account is represented by a tuple of the `AccountInfo`, a `bool` indicating whether the account is writable or not, + /// and a `bool` indicating whether the account is a signer or not. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> &mut Self { + self.instruction + .__remaining_accounts + .extend_from_slice(accounts); + self + } + #[inline(always)] + pub fn invoke(&self) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed(&[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed( + &self, + signers_seeds: &[&[&[u8]]], + ) -> solana_program::entrypoint::ProgramResult { + let args = DepositInstructionArgs { + amount: self.instruction.amount.clone().expect("amount is not set"), + }; + let instruction = DepositCpi { + __program: self.instruction.__program, + + user_account: self + .instruction + .user_account + .expect("user_account is not set"), + + user: self.instruction.user.expect("user is not set"), + + vault: self.instruction.vault.expect("vault is not set"), + + payer: self.instruction.payer.expect("payer is not set"), + + system_program: self + .instruction + .system_program + .expect("system_program is not set"), + __args: args, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct DepositCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_program::account_info::AccountInfo<'a>, + user_account: Option<&'b solana_program::account_info::AccountInfo<'a>>, + user: Option<&'b solana_program::account_info::AccountInfo<'a>>, + vault: Option<&'b solana_program::account_info::AccountInfo<'a>>, + payer: Option<&'b solana_program::account_info::AccountInfo<'a>>, + system_program: Option<&'b solana_program::account_info::AccountInfo<'a>>, + amount: Option, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )>, +} diff --git a/dephy-vending_machine-examples/balance-payment-sdk/src/generated/instructions/initialize.rs b/dephy-vending_machine-examples/balance-payment-sdk/src/generated/instructions/initialize.rs new file mode 100644 index 0000000..3e307bf --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment-sdk/src/generated/instructions/initialize.rs @@ -0,0 +1,475 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +/// Accounts. +pub struct Initialize { + pub global_account: solana_program::pubkey::Pubkey, + + pub authority: solana_program::pubkey::Pubkey, + + pub treasury: solana_program::pubkey::Pubkey, + + pub bot: solana_program::pubkey::Pubkey, + + pub payer: solana_program::pubkey::Pubkey, + + pub system_program: solana_program::pubkey::Pubkey, +} + +impl Initialize { + pub fn instruction(&self) -> solana_program::instruction::Instruction { + self.instruction_with_remaining_accounts(&[]) + } + #[allow(clippy::vec_init_then_push)] + pub fn instruction_with_remaining_accounts( + &self, + remaining_accounts: &[solana_program::instruction::AccountMeta], + ) -> solana_program::instruction::Instruction { + let mut accounts = Vec::with_capacity(6 + remaining_accounts.len()); + accounts.push(solana_program::instruction::AccountMeta::new( + self.global_account, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + self.authority, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + self.treasury, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + self.bot, false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + self.payer, true, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + self.system_program, + false, + )); + accounts.extend_from_slice(remaining_accounts); + let data = InitializeInstructionData::new().try_to_vec().unwrap(); + + solana_program::instruction::Instruction { + program_id: crate::BALANCE_PAYMENT_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct InitializeInstructionData { + discriminator: [u8; 8], +} + +impl InitializeInstructionData { + pub fn new() -> Self { + Self { + discriminator: [175, 175, 109, 31, 13, 152, 155, 237], + } + } +} + +impl Default for InitializeInstructionData { + fn default() -> Self { + Self::new() + } +} + +/// Instruction builder for `Initialize`. +/// +/// ### Accounts: +/// +/// 0. `[writable]` global_account +/// 1. `[]` authority +/// 2. `[]` treasury +/// 3. `[]` bot +/// 4. `[writable, signer]` payer +/// 5. `[optional]` system_program (default to `11111111111111111111111111111111`) +#[derive(Clone, Debug, Default)] +pub struct InitializeBuilder { + global_account: Option, + authority: Option, + treasury: Option, + bot: Option, + payer: Option, + system_program: Option, + __remaining_accounts: Vec, +} + +impl InitializeBuilder { + pub fn new() -> Self { + Self::default() + } + #[inline(always)] + pub fn global_account(&mut self, global_account: solana_program::pubkey::Pubkey) -> &mut Self { + self.global_account = Some(global_account); + self + } + #[inline(always)] + pub fn authority(&mut self, authority: solana_program::pubkey::Pubkey) -> &mut Self { + self.authority = Some(authority); + self + } + #[inline(always)] + pub fn treasury(&mut self, treasury: solana_program::pubkey::Pubkey) -> &mut Self { + self.treasury = Some(treasury); + self + } + #[inline(always)] + pub fn bot(&mut self, bot: solana_program::pubkey::Pubkey) -> &mut Self { + self.bot = Some(bot); + self + } + #[inline(always)] + pub fn payer(&mut self, payer: solana_program::pubkey::Pubkey) -> &mut Self { + self.payer = Some(payer); + self + } + /// `[optional account, default to '11111111111111111111111111111111']` + #[inline(always)] + pub fn system_program(&mut self, system_program: solana_program::pubkey::Pubkey) -> &mut Self { + self.system_program = Some(system_program); + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: solana_program::instruction::AccountMeta, + ) -> &mut Self { + self.__remaining_accounts.push(account); + self + } + /// Add additional accounts to the instruction. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[solana_program::instruction::AccountMeta], + ) -> &mut Self { + self.__remaining_accounts.extend_from_slice(accounts); + self + } + #[allow(clippy::clone_on_copy)] + pub fn instruction(&self) -> solana_program::instruction::Instruction { + let accounts = Initialize { + global_account: self.global_account.expect("global_account is not set"), + authority: self.authority.expect("authority is not set"), + treasury: self.treasury.expect("treasury is not set"), + bot: self.bot.expect("bot is not set"), + payer: self.payer.expect("payer is not set"), + system_program: self + .system_program + .unwrap_or(solana_program::pubkey!("11111111111111111111111111111111")), + }; + + accounts.instruction_with_remaining_accounts(&self.__remaining_accounts) + } +} + +/// `initialize` CPI accounts. +pub struct InitializeCpiAccounts<'a, 'b> { + pub global_account: &'b solana_program::account_info::AccountInfo<'a>, + + pub authority: &'b solana_program::account_info::AccountInfo<'a>, + + pub treasury: &'b solana_program::account_info::AccountInfo<'a>, + + pub bot: &'b solana_program::account_info::AccountInfo<'a>, + + pub payer: &'b solana_program::account_info::AccountInfo<'a>, + + pub system_program: &'b solana_program::account_info::AccountInfo<'a>, +} + +/// `initialize` CPI instruction. +pub struct InitializeCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_program::account_info::AccountInfo<'a>, + + pub global_account: &'b solana_program::account_info::AccountInfo<'a>, + + pub authority: &'b solana_program::account_info::AccountInfo<'a>, + + pub treasury: &'b solana_program::account_info::AccountInfo<'a>, + + pub bot: &'b solana_program::account_info::AccountInfo<'a>, + + pub payer: &'b solana_program::account_info::AccountInfo<'a>, + + pub system_program: &'b solana_program::account_info::AccountInfo<'a>, +} + +impl<'a, 'b> InitializeCpi<'a, 'b> { + pub fn new( + program: &'b solana_program::account_info::AccountInfo<'a>, + accounts: InitializeCpiAccounts<'a, 'b>, + ) -> Self { + Self { + __program: program, + global_account: accounts.global_account, + authority: accounts.authority, + treasury: accounts.treasury, + bot: accounts.bot, + payer: accounts.payer, + system_program: accounts.system_program, + } + } + #[inline(always)] + pub fn invoke(&self) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], &[]) + } + #[inline(always)] + pub fn invoke_with_remaining_accounts( + &self, + remaining_accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], remaining_accounts) + } + #[inline(always)] + pub fn invoke_signed( + &self, + signers_seeds: &[&[&[u8]]], + ) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(signers_seeds, &[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed_with_remaining_accounts( + &self, + signers_seeds: &[&[&[u8]]], + remaining_accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> solana_program::entrypoint::ProgramResult { + let mut accounts = Vec::with_capacity(6 + remaining_accounts.len()); + accounts.push(solana_program::instruction::AccountMeta::new( + *self.global_account.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *self.authority.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *self.treasury.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *self.bot.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + *self.payer.key, + true, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *self.system_program.key, + false, + )); + remaining_accounts.iter().for_each(|remaining_account| { + accounts.push(solana_program::instruction::AccountMeta { + pubkey: *remaining_account.0.key, + is_signer: remaining_account.1, + is_writable: remaining_account.2, + }) + }); + let data = InitializeInstructionData::new().try_to_vec().unwrap(); + + let instruction = solana_program::instruction::Instruction { + program_id: crate::BALANCE_PAYMENT_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(7 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.global_account.clone()); + account_infos.push(self.authority.clone()); + account_infos.push(self.treasury.clone()); + account_infos.push(self.bot.clone()); + account_infos.push(self.payer.clone()); + account_infos.push(self.system_program.clone()); + remaining_accounts + .iter() + .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); + + if signers_seeds.is_empty() { + solana_program::program::invoke(&instruction, &account_infos) + } else { + solana_program::program::invoke_signed(&instruction, &account_infos, signers_seeds) + } + } +} + +/// Instruction builder for `Initialize` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[writable]` global_account +/// 1. `[]` authority +/// 2. `[]` treasury +/// 3. `[]` bot +/// 4. `[writable, signer]` payer +/// 5. `[]` system_program +#[derive(Clone, Debug)] +pub struct InitializeCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> InitializeCpiBuilder<'a, 'b> { + pub fn new(program: &'b solana_program::account_info::AccountInfo<'a>) -> Self { + let instruction = Box::new(InitializeCpiBuilderInstruction { + __program: program, + global_account: None, + authority: None, + treasury: None, + bot: None, + payer: None, + system_program: None, + __remaining_accounts: Vec::new(), + }); + Self { instruction } + } + #[inline(always)] + pub fn global_account( + &mut self, + global_account: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.global_account = Some(global_account); + self + } + #[inline(always)] + pub fn authority( + &mut self, + authority: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.authority = Some(authority); + self + } + #[inline(always)] + pub fn treasury( + &mut self, + treasury: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.treasury = Some(treasury); + self + } + #[inline(always)] + pub fn bot(&mut self, bot: &'b solana_program::account_info::AccountInfo<'a>) -> &mut Self { + self.instruction.bot = Some(bot); + self + } + #[inline(always)] + pub fn payer(&mut self, payer: &'b solana_program::account_info::AccountInfo<'a>) -> &mut Self { + self.instruction.payer = Some(payer); + self + } + #[inline(always)] + pub fn system_program( + &mut self, + system_program: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.system_program = Some(system_program); + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: &'b solana_program::account_info::AccountInfo<'a>, + is_writable: bool, + is_signer: bool, + ) -> &mut Self { + self.instruction + .__remaining_accounts + .push((account, is_writable, is_signer)); + self + } + /// Add additional accounts to the instruction. + /// + /// Each account is represented by a tuple of the `AccountInfo`, a `bool` indicating whether the account is writable or not, + /// and a `bool` indicating whether the account is a signer or not. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> &mut Self { + self.instruction + .__remaining_accounts + .extend_from_slice(accounts); + self + } + #[inline(always)] + pub fn invoke(&self) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed(&[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed( + &self, + signers_seeds: &[&[&[u8]]], + ) -> solana_program::entrypoint::ProgramResult { + let instruction = InitializeCpi { + __program: self.instruction.__program, + + global_account: self + .instruction + .global_account + .expect("global_account is not set"), + + authority: self.instruction.authority.expect("authority is not set"), + + treasury: self.instruction.treasury.expect("treasury is not set"), + + bot: self.instruction.bot.expect("bot is not set"), + + payer: self.instruction.payer.expect("payer is not set"), + + system_program: self + .instruction + .system_program + .expect("system_program is not set"), + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct InitializeCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_program::account_info::AccountInfo<'a>, + global_account: Option<&'b solana_program::account_info::AccountInfo<'a>>, + authority: Option<&'b solana_program::account_info::AccountInfo<'a>>, + treasury: Option<&'b solana_program::account_info::AccountInfo<'a>>, + bot: Option<&'b solana_program::account_info::AccountInfo<'a>>, + payer: Option<&'b solana_program::account_info::AccountInfo<'a>>, + system_program: Option<&'b solana_program::account_info::AccountInfo<'a>>, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )>, +} diff --git a/dephy-vending_machine-examples/balance-payment-sdk/src/generated/instructions/lock.rs b/dephy-vending_machine-examples/balance-payment-sdk/src/generated/instructions/lock.rs new file mode 100644 index 0000000..14c1b79 --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment-sdk/src/generated/instructions/lock.rs @@ -0,0 +1,606 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use crate::generated::types::ED25519RecoverInfo; +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +/// Accounts. +pub struct Lock { + pub global_account: solana_program::pubkey::Pubkey, + + pub user_account: solana_program::pubkey::Pubkey, + + pub user: solana_program::pubkey::Pubkey, + + pub lock_account: solana_program::pubkey::Pubkey, + + pub vault: solana_program::pubkey::Pubkey, + + pub bot: solana_program::pubkey::Pubkey, + + pub payer: solana_program::pubkey::Pubkey, + + pub system_program: solana_program::pubkey::Pubkey, +} + +impl Lock { + pub fn instruction( + &self, + args: LockInstructionArgs, + ) -> solana_program::instruction::Instruction { + self.instruction_with_remaining_accounts(args, &[]) + } + #[allow(clippy::vec_init_then_push)] + pub fn instruction_with_remaining_accounts( + &self, + args: LockInstructionArgs, + remaining_accounts: &[solana_program::instruction::AccountMeta], + ) -> solana_program::instruction::Instruction { + let mut accounts = Vec::with_capacity(8 + remaining_accounts.len()); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + self.global_account, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + self.user_account, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + self.user, false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + self.lock_account, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + self.vault, false, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + self.bot, true, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + self.payer, true, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + self.system_program, + false, + )); + accounts.extend_from_slice(remaining_accounts); + let mut data = LockInstructionData::new().try_to_vec().unwrap(); + let mut args = args.try_to_vec().unwrap(); + data.append(&mut args); + + solana_program::instruction::Instruction { + program_id: crate::BALANCE_PAYMENT_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct LockInstructionData { + discriminator: [u8; 8], +} + +impl LockInstructionData { + pub fn new() -> Self { + Self { + discriminator: [21, 19, 208, 43, 237, 62, 255, 87], + } + } +} + +impl Default for LockInstructionData { + fn default() -> Self { + Self::new() + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct LockInstructionArgs { + pub recover_info: ED25519RecoverInfo, + pub amount: u64, +} + +/// Instruction builder for `Lock`. +/// +/// ### Accounts: +/// +/// 0. `[]` global_account +/// 1. `[writable]` user_account +/// 2. `[writable]` user +/// 3. `[writable]` lock_account +/// 4. `[]` vault +/// 5. `[signer]` bot +/// 6. `[writable, signer]` payer +/// 7. `[optional]` system_program (default to `11111111111111111111111111111111`) +#[derive(Clone, Debug, Default)] +pub struct LockBuilder { + global_account: Option, + user_account: Option, + user: Option, + lock_account: Option, + vault: Option, + bot: Option, + payer: Option, + system_program: Option, + recover_info: Option, + amount: Option, + __remaining_accounts: Vec, +} + +impl LockBuilder { + pub fn new() -> Self { + Self::default() + } + #[inline(always)] + pub fn global_account(&mut self, global_account: solana_program::pubkey::Pubkey) -> &mut Self { + self.global_account = Some(global_account); + self + } + #[inline(always)] + pub fn user_account(&mut self, user_account: solana_program::pubkey::Pubkey) -> &mut Self { + self.user_account = Some(user_account); + self + } + #[inline(always)] + pub fn user(&mut self, user: solana_program::pubkey::Pubkey) -> &mut Self { + self.user = Some(user); + self + } + #[inline(always)] + pub fn lock_account(&mut self, lock_account: solana_program::pubkey::Pubkey) -> &mut Self { + self.lock_account = Some(lock_account); + self + } + #[inline(always)] + pub fn vault(&mut self, vault: solana_program::pubkey::Pubkey) -> &mut Self { + self.vault = Some(vault); + self + } + #[inline(always)] + pub fn bot(&mut self, bot: solana_program::pubkey::Pubkey) -> &mut Self { + self.bot = Some(bot); + self + } + #[inline(always)] + pub fn payer(&mut self, payer: solana_program::pubkey::Pubkey) -> &mut Self { + self.payer = Some(payer); + self + } + /// `[optional account, default to '11111111111111111111111111111111']` + #[inline(always)] + pub fn system_program(&mut self, system_program: solana_program::pubkey::Pubkey) -> &mut Self { + self.system_program = Some(system_program); + self + } + #[inline(always)] + pub fn recover_info(&mut self, recover_info: ED25519RecoverInfo) -> &mut Self { + self.recover_info = Some(recover_info); + self + } + #[inline(always)] + pub fn amount(&mut self, amount: u64) -> &mut Self { + self.amount = Some(amount); + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: solana_program::instruction::AccountMeta, + ) -> &mut Self { + self.__remaining_accounts.push(account); + self + } + /// Add additional accounts to the instruction. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[solana_program::instruction::AccountMeta], + ) -> &mut Self { + self.__remaining_accounts.extend_from_slice(accounts); + self + } + #[allow(clippy::clone_on_copy)] + pub fn instruction(&self) -> solana_program::instruction::Instruction { + let accounts = Lock { + global_account: self.global_account.expect("global_account is not set"), + user_account: self.user_account.expect("user_account is not set"), + user: self.user.expect("user is not set"), + lock_account: self.lock_account.expect("lock_account is not set"), + vault: self.vault.expect("vault is not set"), + bot: self.bot.expect("bot is not set"), + payer: self.payer.expect("payer is not set"), + system_program: self + .system_program + .unwrap_or(solana_program::pubkey!("11111111111111111111111111111111")), + }; + let args = LockInstructionArgs { + recover_info: self.recover_info.clone().expect("recover_info is not set"), + amount: self.amount.clone().expect("amount is not set"), + }; + + accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) + } +} + +/// `lock` CPI accounts. +pub struct LockCpiAccounts<'a, 'b> { + pub global_account: &'b solana_program::account_info::AccountInfo<'a>, + + pub user_account: &'b solana_program::account_info::AccountInfo<'a>, + + pub user: &'b solana_program::account_info::AccountInfo<'a>, + + pub lock_account: &'b solana_program::account_info::AccountInfo<'a>, + + pub vault: &'b solana_program::account_info::AccountInfo<'a>, + + pub bot: &'b solana_program::account_info::AccountInfo<'a>, + + pub payer: &'b solana_program::account_info::AccountInfo<'a>, + + pub system_program: &'b solana_program::account_info::AccountInfo<'a>, +} + +/// `lock` CPI instruction. +pub struct LockCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_program::account_info::AccountInfo<'a>, + + pub global_account: &'b solana_program::account_info::AccountInfo<'a>, + + pub user_account: &'b solana_program::account_info::AccountInfo<'a>, + + pub user: &'b solana_program::account_info::AccountInfo<'a>, + + pub lock_account: &'b solana_program::account_info::AccountInfo<'a>, + + pub vault: &'b solana_program::account_info::AccountInfo<'a>, + + pub bot: &'b solana_program::account_info::AccountInfo<'a>, + + pub payer: &'b solana_program::account_info::AccountInfo<'a>, + + pub system_program: &'b solana_program::account_info::AccountInfo<'a>, + /// The arguments for the instruction. + pub __args: LockInstructionArgs, +} + +impl<'a, 'b> LockCpi<'a, 'b> { + pub fn new( + program: &'b solana_program::account_info::AccountInfo<'a>, + accounts: LockCpiAccounts<'a, 'b>, + args: LockInstructionArgs, + ) -> Self { + Self { + __program: program, + global_account: accounts.global_account, + user_account: accounts.user_account, + user: accounts.user, + lock_account: accounts.lock_account, + vault: accounts.vault, + bot: accounts.bot, + payer: accounts.payer, + system_program: accounts.system_program, + __args: args, + } + } + #[inline(always)] + pub fn invoke(&self) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], &[]) + } + #[inline(always)] + pub fn invoke_with_remaining_accounts( + &self, + remaining_accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], remaining_accounts) + } + #[inline(always)] + pub fn invoke_signed( + &self, + signers_seeds: &[&[&[u8]]], + ) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(signers_seeds, &[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed_with_remaining_accounts( + &self, + signers_seeds: &[&[&[u8]]], + remaining_accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> solana_program::entrypoint::ProgramResult { + let mut accounts = Vec::with_capacity(8 + remaining_accounts.len()); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *self.global_account.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + *self.user_account.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + *self.user.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + *self.lock_account.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *self.vault.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *self.bot.key, + true, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + *self.payer.key, + true, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *self.system_program.key, + false, + )); + remaining_accounts.iter().for_each(|remaining_account| { + accounts.push(solana_program::instruction::AccountMeta { + pubkey: *remaining_account.0.key, + is_signer: remaining_account.1, + is_writable: remaining_account.2, + }) + }); + let mut data = LockInstructionData::new().try_to_vec().unwrap(); + let mut args = self.__args.try_to_vec().unwrap(); + data.append(&mut args); + + let instruction = solana_program::instruction::Instruction { + program_id: crate::BALANCE_PAYMENT_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(9 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.global_account.clone()); + account_infos.push(self.user_account.clone()); + account_infos.push(self.user.clone()); + account_infos.push(self.lock_account.clone()); + account_infos.push(self.vault.clone()); + account_infos.push(self.bot.clone()); + account_infos.push(self.payer.clone()); + account_infos.push(self.system_program.clone()); + remaining_accounts + .iter() + .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); + + if signers_seeds.is_empty() { + solana_program::program::invoke(&instruction, &account_infos) + } else { + solana_program::program::invoke_signed(&instruction, &account_infos, signers_seeds) + } + } +} + +/// Instruction builder for `Lock` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[]` global_account +/// 1. `[writable]` user_account +/// 2. `[writable]` user +/// 3. `[writable]` lock_account +/// 4. `[]` vault +/// 5. `[signer]` bot +/// 6. `[writable, signer]` payer +/// 7. `[]` system_program +#[derive(Clone, Debug)] +pub struct LockCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> LockCpiBuilder<'a, 'b> { + pub fn new(program: &'b solana_program::account_info::AccountInfo<'a>) -> Self { + let instruction = Box::new(LockCpiBuilderInstruction { + __program: program, + global_account: None, + user_account: None, + user: None, + lock_account: None, + vault: None, + bot: None, + payer: None, + system_program: None, + recover_info: None, + amount: None, + __remaining_accounts: Vec::new(), + }); + Self { instruction } + } + #[inline(always)] + pub fn global_account( + &mut self, + global_account: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.global_account = Some(global_account); + self + } + #[inline(always)] + pub fn user_account( + &mut self, + user_account: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.user_account = Some(user_account); + self + } + #[inline(always)] + pub fn user(&mut self, user: &'b solana_program::account_info::AccountInfo<'a>) -> &mut Self { + self.instruction.user = Some(user); + self + } + #[inline(always)] + pub fn lock_account( + &mut self, + lock_account: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.lock_account = Some(lock_account); + self + } + #[inline(always)] + pub fn vault(&mut self, vault: &'b solana_program::account_info::AccountInfo<'a>) -> &mut Self { + self.instruction.vault = Some(vault); + self + } + #[inline(always)] + pub fn bot(&mut self, bot: &'b solana_program::account_info::AccountInfo<'a>) -> &mut Self { + self.instruction.bot = Some(bot); + self + } + #[inline(always)] + pub fn payer(&mut self, payer: &'b solana_program::account_info::AccountInfo<'a>) -> &mut Self { + self.instruction.payer = Some(payer); + self + } + #[inline(always)] + pub fn system_program( + &mut self, + system_program: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.system_program = Some(system_program); + self + } + #[inline(always)] + pub fn recover_info(&mut self, recover_info: ED25519RecoverInfo) -> &mut Self { + self.instruction.recover_info = Some(recover_info); + self + } + #[inline(always)] + pub fn amount(&mut self, amount: u64) -> &mut Self { + self.instruction.amount = Some(amount); + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: &'b solana_program::account_info::AccountInfo<'a>, + is_writable: bool, + is_signer: bool, + ) -> &mut Self { + self.instruction + .__remaining_accounts + .push((account, is_writable, is_signer)); + self + } + /// Add additional accounts to the instruction. + /// + /// Each account is represented by a tuple of the `AccountInfo`, a `bool` indicating whether the account is writable or not, + /// and a `bool` indicating whether the account is a signer or not. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> &mut Self { + self.instruction + .__remaining_accounts + .extend_from_slice(accounts); + self + } + #[inline(always)] + pub fn invoke(&self) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed(&[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed( + &self, + signers_seeds: &[&[&[u8]]], + ) -> solana_program::entrypoint::ProgramResult { + let args = LockInstructionArgs { + recover_info: self + .instruction + .recover_info + .clone() + .expect("recover_info is not set"), + amount: self.instruction.amount.clone().expect("amount is not set"), + }; + let instruction = LockCpi { + __program: self.instruction.__program, + + global_account: self + .instruction + .global_account + .expect("global_account is not set"), + + user_account: self + .instruction + .user_account + .expect("user_account is not set"), + + user: self.instruction.user.expect("user is not set"), + + lock_account: self + .instruction + .lock_account + .expect("lock_account is not set"), + + vault: self.instruction.vault.expect("vault is not set"), + + bot: self.instruction.bot.expect("bot is not set"), + + payer: self.instruction.payer.expect("payer is not set"), + + system_program: self + .instruction + .system_program + .expect("system_program is not set"), + __args: args, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct LockCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_program::account_info::AccountInfo<'a>, + global_account: Option<&'b solana_program::account_info::AccountInfo<'a>>, + user_account: Option<&'b solana_program::account_info::AccountInfo<'a>>, + user: Option<&'b solana_program::account_info::AccountInfo<'a>>, + lock_account: Option<&'b solana_program::account_info::AccountInfo<'a>>, + vault: Option<&'b solana_program::account_info::AccountInfo<'a>>, + bot: Option<&'b solana_program::account_info::AccountInfo<'a>>, + payer: Option<&'b solana_program::account_info::AccountInfo<'a>>, + system_program: Option<&'b solana_program::account_info::AccountInfo<'a>>, + recover_info: Option, + amount: Option, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )>, +} diff --git a/dephy-vending_machine-examples/balance-payment-sdk/src/generated/instructions/mod.rs b/dephy-vending_machine-examples/balance-payment-sdk/src/generated/instructions/mod.rs new file mode 100644 index 0000000..e9e2ab0 --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment-sdk/src/generated/instructions/mod.rs @@ -0,0 +1,26 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +pub(crate) mod r#deposit; +pub(crate) mod r#initialize; +pub(crate) mod r#lock; +pub(crate) mod r#pay; +pub(crate) mod r#register; +pub(crate) mod r#set_bot; +pub(crate) mod r#set_treasury; +pub(crate) mod r#settle; +pub(crate) mod r#withdraw; + +pub use self::r#deposit::*; +pub use self::r#initialize::*; +pub use self::r#lock::*; +pub use self::r#pay::*; +pub use self::r#register::*; +pub use self::r#set_bot::*; +pub use self::r#set_treasury::*; +pub use self::r#settle::*; +pub use self::r#withdraw::*; diff --git a/dephy-vending_machine-examples/balance-payment-sdk/src/generated/instructions/pay.rs b/dephy-vending_machine-examples/balance-payment-sdk/src/generated/instructions/pay.rs new file mode 100644 index 0000000..afe1322 --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment-sdk/src/generated/instructions/pay.rs @@ -0,0 +1,610 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use crate::generated::types::ED25519RecoverInfo; +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +/// Accounts. +pub struct Pay { + pub global_account: solana_program::pubkey::Pubkey, + + pub user_account: solana_program::pubkey::Pubkey, + + pub user: solana_program::pubkey::Pubkey, + + pub treasury: solana_program::pubkey::Pubkey, + + pub vault: solana_program::pubkey::Pubkey, + + pub bot: solana_program::pubkey::Pubkey, + + pub payer: solana_program::pubkey::Pubkey, + + pub system_program: solana_program::pubkey::Pubkey, +} + +impl Pay { + pub fn instruction( + &self, + args: PayInstructionArgs, + ) -> solana_program::instruction::Instruction { + self.instruction_with_remaining_accounts(args, &[]) + } + #[allow(clippy::vec_init_then_push)] + pub fn instruction_with_remaining_accounts( + &self, + args: PayInstructionArgs, + remaining_accounts: &[solana_program::instruction::AccountMeta], + ) -> solana_program::instruction::Instruction { + let mut accounts = Vec::with_capacity(8 + remaining_accounts.len()); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + self.global_account, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + self.user_account, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + self.user, false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + self.treasury, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + self.vault, false, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + self.bot, true, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + self.payer, true, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + self.system_program, + false, + )); + accounts.extend_from_slice(remaining_accounts); + let mut data = PayInstructionData::new().try_to_vec().unwrap(); + let mut args = args.try_to_vec().unwrap(); + data.append(&mut args); + + solana_program::instruction::Instruction { + program_id: crate::BALANCE_PAYMENT_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct PayInstructionData { + discriminator: [u8; 8], +} + +impl PayInstructionData { + pub fn new() -> Self { + Self { + discriminator: [119, 18, 216, 65, 192, 117, 122, 220], + } + } +} + +impl Default for PayInstructionData { + fn default() -> Self { + Self::new() + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct PayInstructionArgs { + pub recover_info: ED25519RecoverInfo, + pub amount_to_transfer: u64, +} + +/// Instruction builder for `Pay`. +/// +/// ### Accounts: +/// +/// 0. `[]` global_account +/// 1. `[writable]` user_account +/// 2. `[writable]` user +/// 3. `[writable]` treasury +/// 4. `[writable]` vault +/// 5. `[signer]` bot +/// 6. `[writable, signer]` payer +/// 7. `[optional]` system_program (default to `11111111111111111111111111111111`) +#[derive(Clone, Debug, Default)] +pub struct PayBuilder { + global_account: Option, + user_account: Option, + user: Option, + treasury: Option, + vault: Option, + bot: Option, + payer: Option, + system_program: Option, + recover_info: Option, + amount_to_transfer: Option, + __remaining_accounts: Vec, +} + +impl PayBuilder { + pub fn new() -> Self { + Self::default() + } + #[inline(always)] + pub fn global_account(&mut self, global_account: solana_program::pubkey::Pubkey) -> &mut Self { + self.global_account = Some(global_account); + self + } + #[inline(always)] + pub fn user_account(&mut self, user_account: solana_program::pubkey::Pubkey) -> &mut Self { + self.user_account = Some(user_account); + self + } + #[inline(always)] + pub fn user(&mut self, user: solana_program::pubkey::Pubkey) -> &mut Self { + self.user = Some(user); + self + } + #[inline(always)] + pub fn treasury(&mut self, treasury: solana_program::pubkey::Pubkey) -> &mut Self { + self.treasury = Some(treasury); + self + } + #[inline(always)] + pub fn vault(&mut self, vault: solana_program::pubkey::Pubkey) -> &mut Self { + self.vault = Some(vault); + self + } + #[inline(always)] + pub fn bot(&mut self, bot: solana_program::pubkey::Pubkey) -> &mut Self { + self.bot = Some(bot); + self + } + #[inline(always)] + pub fn payer(&mut self, payer: solana_program::pubkey::Pubkey) -> &mut Self { + self.payer = Some(payer); + self + } + /// `[optional account, default to '11111111111111111111111111111111']` + #[inline(always)] + pub fn system_program(&mut self, system_program: solana_program::pubkey::Pubkey) -> &mut Self { + self.system_program = Some(system_program); + self + } + #[inline(always)] + pub fn recover_info(&mut self, recover_info: ED25519RecoverInfo) -> &mut Self { + self.recover_info = Some(recover_info); + self + } + #[inline(always)] + pub fn amount_to_transfer(&mut self, amount_to_transfer: u64) -> &mut Self { + self.amount_to_transfer = Some(amount_to_transfer); + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: solana_program::instruction::AccountMeta, + ) -> &mut Self { + self.__remaining_accounts.push(account); + self + } + /// Add additional accounts to the instruction. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[solana_program::instruction::AccountMeta], + ) -> &mut Self { + self.__remaining_accounts.extend_from_slice(accounts); + self + } + #[allow(clippy::clone_on_copy)] + pub fn instruction(&self) -> solana_program::instruction::Instruction { + let accounts = Pay { + global_account: self.global_account.expect("global_account is not set"), + user_account: self.user_account.expect("user_account is not set"), + user: self.user.expect("user is not set"), + treasury: self.treasury.expect("treasury is not set"), + vault: self.vault.expect("vault is not set"), + bot: self.bot.expect("bot is not set"), + payer: self.payer.expect("payer is not set"), + system_program: self + .system_program + .unwrap_or(solana_program::pubkey!("11111111111111111111111111111111")), + }; + let args = PayInstructionArgs { + recover_info: self.recover_info.clone().expect("recover_info is not set"), + amount_to_transfer: self + .amount_to_transfer + .clone() + .expect("amount_to_transfer is not set"), + }; + + accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) + } +} + +/// `pay` CPI accounts. +pub struct PayCpiAccounts<'a, 'b> { + pub global_account: &'b solana_program::account_info::AccountInfo<'a>, + + pub user_account: &'b solana_program::account_info::AccountInfo<'a>, + + pub user: &'b solana_program::account_info::AccountInfo<'a>, + + pub treasury: &'b solana_program::account_info::AccountInfo<'a>, + + pub vault: &'b solana_program::account_info::AccountInfo<'a>, + + pub bot: &'b solana_program::account_info::AccountInfo<'a>, + + pub payer: &'b solana_program::account_info::AccountInfo<'a>, + + pub system_program: &'b solana_program::account_info::AccountInfo<'a>, +} + +/// `pay` CPI instruction. +pub struct PayCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_program::account_info::AccountInfo<'a>, + + pub global_account: &'b solana_program::account_info::AccountInfo<'a>, + + pub user_account: &'b solana_program::account_info::AccountInfo<'a>, + + pub user: &'b solana_program::account_info::AccountInfo<'a>, + + pub treasury: &'b solana_program::account_info::AccountInfo<'a>, + + pub vault: &'b solana_program::account_info::AccountInfo<'a>, + + pub bot: &'b solana_program::account_info::AccountInfo<'a>, + + pub payer: &'b solana_program::account_info::AccountInfo<'a>, + + pub system_program: &'b solana_program::account_info::AccountInfo<'a>, + /// The arguments for the instruction. + pub __args: PayInstructionArgs, +} + +impl<'a, 'b> PayCpi<'a, 'b> { + pub fn new( + program: &'b solana_program::account_info::AccountInfo<'a>, + accounts: PayCpiAccounts<'a, 'b>, + args: PayInstructionArgs, + ) -> Self { + Self { + __program: program, + global_account: accounts.global_account, + user_account: accounts.user_account, + user: accounts.user, + treasury: accounts.treasury, + vault: accounts.vault, + bot: accounts.bot, + payer: accounts.payer, + system_program: accounts.system_program, + __args: args, + } + } + #[inline(always)] + pub fn invoke(&self) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], &[]) + } + #[inline(always)] + pub fn invoke_with_remaining_accounts( + &self, + remaining_accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], remaining_accounts) + } + #[inline(always)] + pub fn invoke_signed( + &self, + signers_seeds: &[&[&[u8]]], + ) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(signers_seeds, &[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed_with_remaining_accounts( + &self, + signers_seeds: &[&[&[u8]]], + remaining_accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> solana_program::entrypoint::ProgramResult { + let mut accounts = Vec::with_capacity(8 + remaining_accounts.len()); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *self.global_account.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + *self.user_account.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + *self.user.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + *self.treasury.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + *self.vault.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *self.bot.key, + true, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + *self.payer.key, + true, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *self.system_program.key, + false, + )); + remaining_accounts.iter().for_each(|remaining_account| { + accounts.push(solana_program::instruction::AccountMeta { + pubkey: *remaining_account.0.key, + is_signer: remaining_account.1, + is_writable: remaining_account.2, + }) + }); + let mut data = PayInstructionData::new().try_to_vec().unwrap(); + let mut args = self.__args.try_to_vec().unwrap(); + data.append(&mut args); + + let instruction = solana_program::instruction::Instruction { + program_id: crate::BALANCE_PAYMENT_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(9 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.global_account.clone()); + account_infos.push(self.user_account.clone()); + account_infos.push(self.user.clone()); + account_infos.push(self.treasury.clone()); + account_infos.push(self.vault.clone()); + account_infos.push(self.bot.clone()); + account_infos.push(self.payer.clone()); + account_infos.push(self.system_program.clone()); + remaining_accounts + .iter() + .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); + + if signers_seeds.is_empty() { + solana_program::program::invoke(&instruction, &account_infos) + } else { + solana_program::program::invoke_signed(&instruction, &account_infos, signers_seeds) + } + } +} + +/// Instruction builder for `Pay` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[]` global_account +/// 1. `[writable]` user_account +/// 2. `[writable]` user +/// 3. `[writable]` treasury +/// 4. `[writable]` vault +/// 5. `[signer]` bot +/// 6. `[writable, signer]` payer +/// 7. `[]` system_program +#[derive(Clone, Debug)] +pub struct PayCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> PayCpiBuilder<'a, 'b> { + pub fn new(program: &'b solana_program::account_info::AccountInfo<'a>) -> Self { + let instruction = Box::new(PayCpiBuilderInstruction { + __program: program, + global_account: None, + user_account: None, + user: None, + treasury: None, + vault: None, + bot: None, + payer: None, + system_program: None, + recover_info: None, + amount_to_transfer: None, + __remaining_accounts: Vec::new(), + }); + Self { instruction } + } + #[inline(always)] + pub fn global_account( + &mut self, + global_account: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.global_account = Some(global_account); + self + } + #[inline(always)] + pub fn user_account( + &mut self, + user_account: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.user_account = Some(user_account); + self + } + #[inline(always)] + pub fn user(&mut self, user: &'b solana_program::account_info::AccountInfo<'a>) -> &mut Self { + self.instruction.user = Some(user); + self + } + #[inline(always)] + pub fn treasury( + &mut self, + treasury: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.treasury = Some(treasury); + self + } + #[inline(always)] + pub fn vault(&mut self, vault: &'b solana_program::account_info::AccountInfo<'a>) -> &mut Self { + self.instruction.vault = Some(vault); + self + } + #[inline(always)] + pub fn bot(&mut self, bot: &'b solana_program::account_info::AccountInfo<'a>) -> &mut Self { + self.instruction.bot = Some(bot); + self + } + #[inline(always)] + pub fn payer(&mut self, payer: &'b solana_program::account_info::AccountInfo<'a>) -> &mut Self { + self.instruction.payer = Some(payer); + self + } + #[inline(always)] + pub fn system_program( + &mut self, + system_program: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.system_program = Some(system_program); + self + } + #[inline(always)] + pub fn recover_info(&mut self, recover_info: ED25519RecoverInfo) -> &mut Self { + self.instruction.recover_info = Some(recover_info); + self + } + #[inline(always)] + pub fn amount_to_transfer(&mut self, amount_to_transfer: u64) -> &mut Self { + self.instruction.amount_to_transfer = Some(amount_to_transfer); + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: &'b solana_program::account_info::AccountInfo<'a>, + is_writable: bool, + is_signer: bool, + ) -> &mut Self { + self.instruction + .__remaining_accounts + .push((account, is_writable, is_signer)); + self + } + /// Add additional accounts to the instruction. + /// + /// Each account is represented by a tuple of the `AccountInfo`, a `bool` indicating whether the account is writable or not, + /// and a `bool` indicating whether the account is a signer or not. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> &mut Self { + self.instruction + .__remaining_accounts + .extend_from_slice(accounts); + self + } + #[inline(always)] + pub fn invoke(&self) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed(&[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed( + &self, + signers_seeds: &[&[&[u8]]], + ) -> solana_program::entrypoint::ProgramResult { + let args = PayInstructionArgs { + recover_info: self + .instruction + .recover_info + .clone() + .expect("recover_info is not set"), + amount_to_transfer: self + .instruction + .amount_to_transfer + .clone() + .expect("amount_to_transfer is not set"), + }; + let instruction = PayCpi { + __program: self.instruction.__program, + + global_account: self + .instruction + .global_account + .expect("global_account is not set"), + + user_account: self + .instruction + .user_account + .expect("user_account is not set"), + + user: self.instruction.user.expect("user is not set"), + + treasury: self.instruction.treasury.expect("treasury is not set"), + + vault: self.instruction.vault.expect("vault is not set"), + + bot: self.instruction.bot.expect("bot is not set"), + + payer: self.instruction.payer.expect("payer is not set"), + + system_program: self + .instruction + .system_program + .expect("system_program is not set"), + __args: args, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct PayCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_program::account_info::AccountInfo<'a>, + global_account: Option<&'b solana_program::account_info::AccountInfo<'a>>, + user_account: Option<&'b solana_program::account_info::AccountInfo<'a>>, + user: Option<&'b solana_program::account_info::AccountInfo<'a>>, + treasury: Option<&'b solana_program::account_info::AccountInfo<'a>>, + vault: Option<&'b solana_program::account_info::AccountInfo<'a>>, + bot: Option<&'b solana_program::account_info::AccountInfo<'a>>, + payer: Option<&'b solana_program::account_info::AccountInfo<'a>>, + system_program: Option<&'b solana_program::account_info::AccountInfo<'a>>, + recover_info: Option, + amount_to_transfer: Option, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )>, +} diff --git a/dephy-vending_machine-examples/balance-payment-sdk/src/generated/instructions/register.rs b/dephy-vending_machine-examples/balance-payment-sdk/src/generated/instructions/register.rs new file mode 100644 index 0000000..f9160de --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment-sdk/src/generated/instructions/register.rs @@ -0,0 +1,434 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +/// Accounts. +pub struct Register { + pub user_account: solana_program::pubkey::Pubkey, + + pub user: solana_program::pubkey::Pubkey, + + pub vault: solana_program::pubkey::Pubkey, + + pub payer: solana_program::pubkey::Pubkey, + + pub system_program: solana_program::pubkey::Pubkey, +} + +impl Register { + pub fn instruction(&self) -> solana_program::instruction::Instruction { + self.instruction_with_remaining_accounts(&[]) + } + #[allow(clippy::vec_init_then_push)] + pub fn instruction_with_remaining_accounts( + &self, + remaining_accounts: &[solana_program::instruction::AccountMeta], + ) -> solana_program::instruction::Instruction { + let mut accounts = Vec::with_capacity(5 + remaining_accounts.len()); + accounts.push(solana_program::instruction::AccountMeta::new( + self.user_account, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + self.user, true, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + self.vault, false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + self.payer, true, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + self.system_program, + false, + )); + accounts.extend_from_slice(remaining_accounts); + let data = RegisterInstructionData::new().try_to_vec().unwrap(); + + solana_program::instruction::Instruction { + program_id: crate::BALANCE_PAYMENT_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct RegisterInstructionData { + discriminator: [u8; 8], +} + +impl RegisterInstructionData { + pub fn new() -> Self { + Self { + discriminator: [211, 124, 67, 15, 211, 194, 178, 240], + } + } +} + +impl Default for RegisterInstructionData { + fn default() -> Self { + Self::new() + } +} + +/// Instruction builder for `Register`. +/// +/// ### Accounts: +/// +/// 0. `[writable]` user_account +/// 1. `[signer]` user +/// 2. `[]` vault +/// 3. `[writable, signer]` payer +/// 4. `[optional]` system_program (default to `11111111111111111111111111111111`) +#[derive(Clone, Debug, Default)] +pub struct RegisterBuilder { + user_account: Option, + user: Option, + vault: Option, + payer: Option, + system_program: Option, + __remaining_accounts: Vec, +} + +impl RegisterBuilder { + pub fn new() -> Self { + Self::default() + } + #[inline(always)] + pub fn user_account(&mut self, user_account: solana_program::pubkey::Pubkey) -> &mut Self { + self.user_account = Some(user_account); + self + } + #[inline(always)] + pub fn user(&mut self, user: solana_program::pubkey::Pubkey) -> &mut Self { + self.user = Some(user); + self + } + #[inline(always)] + pub fn vault(&mut self, vault: solana_program::pubkey::Pubkey) -> &mut Self { + self.vault = Some(vault); + self + } + #[inline(always)] + pub fn payer(&mut self, payer: solana_program::pubkey::Pubkey) -> &mut Self { + self.payer = Some(payer); + self + } + /// `[optional account, default to '11111111111111111111111111111111']` + #[inline(always)] + pub fn system_program(&mut self, system_program: solana_program::pubkey::Pubkey) -> &mut Self { + self.system_program = Some(system_program); + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: solana_program::instruction::AccountMeta, + ) -> &mut Self { + self.__remaining_accounts.push(account); + self + } + /// Add additional accounts to the instruction. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[solana_program::instruction::AccountMeta], + ) -> &mut Self { + self.__remaining_accounts.extend_from_slice(accounts); + self + } + #[allow(clippy::clone_on_copy)] + pub fn instruction(&self) -> solana_program::instruction::Instruction { + let accounts = Register { + user_account: self.user_account.expect("user_account is not set"), + user: self.user.expect("user is not set"), + vault: self.vault.expect("vault is not set"), + payer: self.payer.expect("payer is not set"), + system_program: self + .system_program + .unwrap_or(solana_program::pubkey!("11111111111111111111111111111111")), + }; + + accounts.instruction_with_remaining_accounts(&self.__remaining_accounts) + } +} + +/// `register` CPI accounts. +pub struct RegisterCpiAccounts<'a, 'b> { + pub user_account: &'b solana_program::account_info::AccountInfo<'a>, + + pub user: &'b solana_program::account_info::AccountInfo<'a>, + + pub vault: &'b solana_program::account_info::AccountInfo<'a>, + + pub payer: &'b solana_program::account_info::AccountInfo<'a>, + + pub system_program: &'b solana_program::account_info::AccountInfo<'a>, +} + +/// `register` CPI instruction. +pub struct RegisterCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_program::account_info::AccountInfo<'a>, + + pub user_account: &'b solana_program::account_info::AccountInfo<'a>, + + pub user: &'b solana_program::account_info::AccountInfo<'a>, + + pub vault: &'b solana_program::account_info::AccountInfo<'a>, + + pub payer: &'b solana_program::account_info::AccountInfo<'a>, + + pub system_program: &'b solana_program::account_info::AccountInfo<'a>, +} + +impl<'a, 'b> RegisterCpi<'a, 'b> { + pub fn new( + program: &'b solana_program::account_info::AccountInfo<'a>, + accounts: RegisterCpiAccounts<'a, 'b>, + ) -> Self { + Self { + __program: program, + user_account: accounts.user_account, + user: accounts.user, + vault: accounts.vault, + payer: accounts.payer, + system_program: accounts.system_program, + } + } + #[inline(always)] + pub fn invoke(&self) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], &[]) + } + #[inline(always)] + pub fn invoke_with_remaining_accounts( + &self, + remaining_accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], remaining_accounts) + } + #[inline(always)] + pub fn invoke_signed( + &self, + signers_seeds: &[&[&[u8]]], + ) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(signers_seeds, &[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed_with_remaining_accounts( + &self, + signers_seeds: &[&[&[u8]]], + remaining_accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> solana_program::entrypoint::ProgramResult { + let mut accounts = Vec::with_capacity(5 + remaining_accounts.len()); + accounts.push(solana_program::instruction::AccountMeta::new( + *self.user_account.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *self.user.key, + true, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *self.vault.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + *self.payer.key, + true, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *self.system_program.key, + false, + )); + remaining_accounts.iter().for_each(|remaining_account| { + accounts.push(solana_program::instruction::AccountMeta { + pubkey: *remaining_account.0.key, + is_signer: remaining_account.1, + is_writable: remaining_account.2, + }) + }); + let data = RegisterInstructionData::new().try_to_vec().unwrap(); + + let instruction = solana_program::instruction::Instruction { + program_id: crate::BALANCE_PAYMENT_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(6 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.user_account.clone()); + account_infos.push(self.user.clone()); + account_infos.push(self.vault.clone()); + account_infos.push(self.payer.clone()); + account_infos.push(self.system_program.clone()); + remaining_accounts + .iter() + .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); + + if signers_seeds.is_empty() { + solana_program::program::invoke(&instruction, &account_infos) + } else { + solana_program::program::invoke_signed(&instruction, &account_infos, signers_seeds) + } + } +} + +/// Instruction builder for `Register` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[writable]` user_account +/// 1. `[signer]` user +/// 2. `[]` vault +/// 3. `[writable, signer]` payer +/// 4. `[]` system_program +#[derive(Clone, Debug)] +pub struct RegisterCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> RegisterCpiBuilder<'a, 'b> { + pub fn new(program: &'b solana_program::account_info::AccountInfo<'a>) -> Self { + let instruction = Box::new(RegisterCpiBuilderInstruction { + __program: program, + user_account: None, + user: None, + vault: None, + payer: None, + system_program: None, + __remaining_accounts: Vec::new(), + }); + Self { instruction } + } + #[inline(always)] + pub fn user_account( + &mut self, + user_account: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.user_account = Some(user_account); + self + } + #[inline(always)] + pub fn user(&mut self, user: &'b solana_program::account_info::AccountInfo<'a>) -> &mut Self { + self.instruction.user = Some(user); + self + } + #[inline(always)] + pub fn vault(&mut self, vault: &'b solana_program::account_info::AccountInfo<'a>) -> &mut Self { + self.instruction.vault = Some(vault); + self + } + #[inline(always)] + pub fn payer(&mut self, payer: &'b solana_program::account_info::AccountInfo<'a>) -> &mut Self { + self.instruction.payer = Some(payer); + self + } + #[inline(always)] + pub fn system_program( + &mut self, + system_program: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.system_program = Some(system_program); + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: &'b solana_program::account_info::AccountInfo<'a>, + is_writable: bool, + is_signer: bool, + ) -> &mut Self { + self.instruction + .__remaining_accounts + .push((account, is_writable, is_signer)); + self + } + /// Add additional accounts to the instruction. + /// + /// Each account is represented by a tuple of the `AccountInfo`, a `bool` indicating whether the account is writable or not, + /// and a `bool` indicating whether the account is a signer or not. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> &mut Self { + self.instruction + .__remaining_accounts + .extend_from_slice(accounts); + self + } + #[inline(always)] + pub fn invoke(&self) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed(&[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed( + &self, + signers_seeds: &[&[&[u8]]], + ) -> solana_program::entrypoint::ProgramResult { + let instruction = RegisterCpi { + __program: self.instruction.__program, + + user_account: self + .instruction + .user_account + .expect("user_account is not set"), + + user: self.instruction.user.expect("user is not set"), + + vault: self.instruction.vault.expect("vault is not set"), + + payer: self.instruction.payer.expect("payer is not set"), + + system_program: self + .instruction + .system_program + .expect("system_program is not set"), + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct RegisterCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_program::account_info::AccountInfo<'a>, + user_account: Option<&'b solana_program::account_info::AccountInfo<'a>>, + user: Option<&'b solana_program::account_info::AccountInfo<'a>>, + vault: Option<&'b solana_program::account_info::AccountInfo<'a>>, + payer: Option<&'b solana_program::account_info::AccountInfo<'a>>, + system_program: Option<&'b solana_program::account_info::AccountInfo<'a>>, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )>, +} diff --git a/dephy-vending_machine-examples/balance-payment-sdk/src/generated/instructions/set_bot.rs b/dephy-vending_machine-examples/balance-payment-sdk/src/generated/instructions/set_bot.rs new file mode 100644 index 0000000..4950961 --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment-sdk/src/generated/instructions/set_bot.rs @@ -0,0 +1,395 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +/// Accounts. +pub struct SetBot { + pub global_account: solana_program::pubkey::Pubkey, + + pub authority: solana_program::pubkey::Pubkey, + + pub bot: solana_program::pubkey::Pubkey, + + pub payer: solana_program::pubkey::Pubkey, +} + +impl SetBot { + pub fn instruction(&self) -> solana_program::instruction::Instruction { + self.instruction_with_remaining_accounts(&[]) + } + #[allow(clippy::vec_init_then_push)] + pub fn instruction_with_remaining_accounts( + &self, + remaining_accounts: &[solana_program::instruction::AccountMeta], + ) -> solana_program::instruction::Instruction { + let mut accounts = Vec::with_capacity(4 + remaining_accounts.len()); + accounts.push(solana_program::instruction::AccountMeta::new( + self.global_account, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + self.authority, + true, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + self.bot, false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + self.payer, true, + )); + accounts.extend_from_slice(remaining_accounts); + let data = SetBotInstructionData::new().try_to_vec().unwrap(); + + solana_program::instruction::Instruction { + program_id: crate::BALANCE_PAYMENT_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct SetBotInstructionData { + discriminator: [u8; 8], +} + +impl SetBotInstructionData { + pub fn new() -> Self { + Self { + discriminator: [136, 185, 99, 236, 200, 131, 204, 118], + } + } +} + +impl Default for SetBotInstructionData { + fn default() -> Self { + Self::new() + } +} + +/// Instruction builder for `SetBot`. +/// +/// ### Accounts: +/// +/// 0. `[writable]` global_account +/// 1. `[signer]` authority +/// 2. `[]` bot +/// 3. `[writable, signer]` payer +#[derive(Clone, Debug, Default)] +pub struct SetBotBuilder { + global_account: Option, + authority: Option, + bot: Option, + payer: Option, + __remaining_accounts: Vec, +} + +impl SetBotBuilder { + pub fn new() -> Self { + Self::default() + } + #[inline(always)] + pub fn global_account(&mut self, global_account: solana_program::pubkey::Pubkey) -> &mut Self { + self.global_account = Some(global_account); + self + } + #[inline(always)] + pub fn authority(&mut self, authority: solana_program::pubkey::Pubkey) -> &mut Self { + self.authority = Some(authority); + self + } + #[inline(always)] + pub fn bot(&mut self, bot: solana_program::pubkey::Pubkey) -> &mut Self { + self.bot = Some(bot); + self + } + #[inline(always)] + pub fn payer(&mut self, payer: solana_program::pubkey::Pubkey) -> &mut Self { + self.payer = Some(payer); + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: solana_program::instruction::AccountMeta, + ) -> &mut Self { + self.__remaining_accounts.push(account); + self + } + /// Add additional accounts to the instruction. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[solana_program::instruction::AccountMeta], + ) -> &mut Self { + self.__remaining_accounts.extend_from_slice(accounts); + self + } + #[allow(clippy::clone_on_copy)] + pub fn instruction(&self) -> solana_program::instruction::Instruction { + let accounts = SetBot { + global_account: self.global_account.expect("global_account is not set"), + authority: self.authority.expect("authority is not set"), + bot: self.bot.expect("bot is not set"), + payer: self.payer.expect("payer is not set"), + }; + + accounts.instruction_with_remaining_accounts(&self.__remaining_accounts) + } +} + +/// `set_bot` CPI accounts. +pub struct SetBotCpiAccounts<'a, 'b> { + pub global_account: &'b solana_program::account_info::AccountInfo<'a>, + + pub authority: &'b solana_program::account_info::AccountInfo<'a>, + + pub bot: &'b solana_program::account_info::AccountInfo<'a>, + + pub payer: &'b solana_program::account_info::AccountInfo<'a>, +} + +/// `set_bot` CPI instruction. +pub struct SetBotCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_program::account_info::AccountInfo<'a>, + + pub global_account: &'b solana_program::account_info::AccountInfo<'a>, + + pub authority: &'b solana_program::account_info::AccountInfo<'a>, + + pub bot: &'b solana_program::account_info::AccountInfo<'a>, + + pub payer: &'b solana_program::account_info::AccountInfo<'a>, +} + +impl<'a, 'b> SetBotCpi<'a, 'b> { + pub fn new( + program: &'b solana_program::account_info::AccountInfo<'a>, + accounts: SetBotCpiAccounts<'a, 'b>, + ) -> Self { + Self { + __program: program, + global_account: accounts.global_account, + authority: accounts.authority, + bot: accounts.bot, + payer: accounts.payer, + } + } + #[inline(always)] + pub fn invoke(&self) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], &[]) + } + #[inline(always)] + pub fn invoke_with_remaining_accounts( + &self, + remaining_accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], remaining_accounts) + } + #[inline(always)] + pub fn invoke_signed( + &self, + signers_seeds: &[&[&[u8]]], + ) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(signers_seeds, &[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed_with_remaining_accounts( + &self, + signers_seeds: &[&[&[u8]]], + remaining_accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> solana_program::entrypoint::ProgramResult { + let mut accounts = Vec::with_capacity(4 + remaining_accounts.len()); + accounts.push(solana_program::instruction::AccountMeta::new( + *self.global_account.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *self.authority.key, + true, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *self.bot.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + *self.payer.key, + true, + )); + remaining_accounts.iter().for_each(|remaining_account| { + accounts.push(solana_program::instruction::AccountMeta { + pubkey: *remaining_account.0.key, + is_signer: remaining_account.1, + is_writable: remaining_account.2, + }) + }); + let data = SetBotInstructionData::new().try_to_vec().unwrap(); + + let instruction = solana_program::instruction::Instruction { + program_id: crate::BALANCE_PAYMENT_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(5 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.global_account.clone()); + account_infos.push(self.authority.clone()); + account_infos.push(self.bot.clone()); + account_infos.push(self.payer.clone()); + remaining_accounts + .iter() + .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); + + if signers_seeds.is_empty() { + solana_program::program::invoke(&instruction, &account_infos) + } else { + solana_program::program::invoke_signed(&instruction, &account_infos, signers_seeds) + } + } +} + +/// Instruction builder for `SetBot` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[writable]` global_account +/// 1. `[signer]` authority +/// 2. `[]` bot +/// 3. `[writable, signer]` payer +#[derive(Clone, Debug)] +pub struct SetBotCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> SetBotCpiBuilder<'a, 'b> { + pub fn new(program: &'b solana_program::account_info::AccountInfo<'a>) -> Self { + let instruction = Box::new(SetBotCpiBuilderInstruction { + __program: program, + global_account: None, + authority: None, + bot: None, + payer: None, + __remaining_accounts: Vec::new(), + }); + Self { instruction } + } + #[inline(always)] + pub fn global_account( + &mut self, + global_account: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.global_account = Some(global_account); + self + } + #[inline(always)] + pub fn authority( + &mut self, + authority: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.authority = Some(authority); + self + } + #[inline(always)] + pub fn bot(&mut self, bot: &'b solana_program::account_info::AccountInfo<'a>) -> &mut Self { + self.instruction.bot = Some(bot); + self + } + #[inline(always)] + pub fn payer(&mut self, payer: &'b solana_program::account_info::AccountInfo<'a>) -> &mut Self { + self.instruction.payer = Some(payer); + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: &'b solana_program::account_info::AccountInfo<'a>, + is_writable: bool, + is_signer: bool, + ) -> &mut Self { + self.instruction + .__remaining_accounts + .push((account, is_writable, is_signer)); + self + } + /// Add additional accounts to the instruction. + /// + /// Each account is represented by a tuple of the `AccountInfo`, a `bool` indicating whether the account is writable or not, + /// and a `bool` indicating whether the account is a signer or not. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> &mut Self { + self.instruction + .__remaining_accounts + .extend_from_slice(accounts); + self + } + #[inline(always)] + pub fn invoke(&self) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed(&[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed( + &self, + signers_seeds: &[&[&[u8]]], + ) -> solana_program::entrypoint::ProgramResult { + let instruction = SetBotCpi { + __program: self.instruction.__program, + + global_account: self + .instruction + .global_account + .expect("global_account is not set"), + + authority: self.instruction.authority.expect("authority is not set"), + + bot: self.instruction.bot.expect("bot is not set"), + + payer: self.instruction.payer.expect("payer is not set"), + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct SetBotCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_program::account_info::AccountInfo<'a>, + global_account: Option<&'b solana_program::account_info::AccountInfo<'a>>, + authority: Option<&'b solana_program::account_info::AccountInfo<'a>>, + bot: Option<&'b solana_program::account_info::AccountInfo<'a>>, + payer: Option<&'b solana_program::account_info::AccountInfo<'a>>, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )>, +} diff --git a/dephy-vending_machine-examples/balance-payment-sdk/src/generated/instructions/set_treasury.rs b/dephy-vending_machine-examples/balance-payment-sdk/src/generated/instructions/set_treasury.rs new file mode 100644 index 0000000..edc79a7 --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment-sdk/src/generated/instructions/set_treasury.rs @@ -0,0 +1,399 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +/// Accounts. +pub struct SetTreasury { + pub global_account: solana_program::pubkey::Pubkey, + + pub authority: solana_program::pubkey::Pubkey, + + pub treasury: solana_program::pubkey::Pubkey, + + pub payer: solana_program::pubkey::Pubkey, +} + +impl SetTreasury { + pub fn instruction(&self) -> solana_program::instruction::Instruction { + self.instruction_with_remaining_accounts(&[]) + } + #[allow(clippy::vec_init_then_push)] + pub fn instruction_with_remaining_accounts( + &self, + remaining_accounts: &[solana_program::instruction::AccountMeta], + ) -> solana_program::instruction::Instruction { + let mut accounts = Vec::with_capacity(4 + remaining_accounts.len()); + accounts.push(solana_program::instruction::AccountMeta::new( + self.global_account, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + self.authority, + true, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + self.treasury, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + self.payer, true, + )); + accounts.extend_from_slice(remaining_accounts); + let data = SetTreasuryInstructionData::new().try_to_vec().unwrap(); + + solana_program::instruction::Instruction { + program_id: crate::BALANCE_PAYMENT_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct SetTreasuryInstructionData { + discriminator: [u8; 8], +} + +impl SetTreasuryInstructionData { + pub fn new() -> Self { + Self { + discriminator: [57, 97, 196, 95, 195, 206, 106, 136], + } + } +} + +impl Default for SetTreasuryInstructionData { + fn default() -> Self { + Self::new() + } +} + +/// Instruction builder for `SetTreasury`. +/// +/// ### Accounts: +/// +/// 0. `[writable]` global_account +/// 1. `[signer]` authority +/// 2. `[]` treasury +/// 3. `[writable, signer]` payer +#[derive(Clone, Debug, Default)] +pub struct SetTreasuryBuilder { + global_account: Option, + authority: Option, + treasury: Option, + payer: Option, + __remaining_accounts: Vec, +} + +impl SetTreasuryBuilder { + pub fn new() -> Self { + Self::default() + } + #[inline(always)] + pub fn global_account(&mut self, global_account: solana_program::pubkey::Pubkey) -> &mut Self { + self.global_account = Some(global_account); + self + } + #[inline(always)] + pub fn authority(&mut self, authority: solana_program::pubkey::Pubkey) -> &mut Self { + self.authority = Some(authority); + self + } + #[inline(always)] + pub fn treasury(&mut self, treasury: solana_program::pubkey::Pubkey) -> &mut Self { + self.treasury = Some(treasury); + self + } + #[inline(always)] + pub fn payer(&mut self, payer: solana_program::pubkey::Pubkey) -> &mut Self { + self.payer = Some(payer); + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: solana_program::instruction::AccountMeta, + ) -> &mut Self { + self.__remaining_accounts.push(account); + self + } + /// Add additional accounts to the instruction. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[solana_program::instruction::AccountMeta], + ) -> &mut Self { + self.__remaining_accounts.extend_from_slice(accounts); + self + } + #[allow(clippy::clone_on_copy)] + pub fn instruction(&self) -> solana_program::instruction::Instruction { + let accounts = SetTreasury { + global_account: self.global_account.expect("global_account is not set"), + authority: self.authority.expect("authority is not set"), + treasury: self.treasury.expect("treasury is not set"), + payer: self.payer.expect("payer is not set"), + }; + + accounts.instruction_with_remaining_accounts(&self.__remaining_accounts) + } +} + +/// `set_treasury` CPI accounts. +pub struct SetTreasuryCpiAccounts<'a, 'b> { + pub global_account: &'b solana_program::account_info::AccountInfo<'a>, + + pub authority: &'b solana_program::account_info::AccountInfo<'a>, + + pub treasury: &'b solana_program::account_info::AccountInfo<'a>, + + pub payer: &'b solana_program::account_info::AccountInfo<'a>, +} + +/// `set_treasury` CPI instruction. +pub struct SetTreasuryCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_program::account_info::AccountInfo<'a>, + + pub global_account: &'b solana_program::account_info::AccountInfo<'a>, + + pub authority: &'b solana_program::account_info::AccountInfo<'a>, + + pub treasury: &'b solana_program::account_info::AccountInfo<'a>, + + pub payer: &'b solana_program::account_info::AccountInfo<'a>, +} + +impl<'a, 'b> SetTreasuryCpi<'a, 'b> { + pub fn new( + program: &'b solana_program::account_info::AccountInfo<'a>, + accounts: SetTreasuryCpiAccounts<'a, 'b>, + ) -> Self { + Self { + __program: program, + global_account: accounts.global_account, + authority: accounts.authority, + treasury: accounts.treasury, + payer: accounts.payer, + } + } + #[inline(always)] + pub fn invoke(&self) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], &[]) + } + #[inline(always)] + pub fn invoke_with_remaining_accounts( + &self, + remaining_accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], remaining_accounts) + } + #[inline(always)] + pub fn invoke_signed( + &self, + signers_seeds: &[&[&[u8]]], + ) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(signers_seeds, &[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed_with_remaining_accounts( + &self, + signers_seeds: &[&[&[u8]]], + remaining_accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> solana_program::entrypoint::ProgramResult { + let mut accounts = Vec::with_capacity(4 + remaining_accounts.len()); + accounts.push(solana_program::instruction::AccountMeta::new( + *self.global_account.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *self.authority.key, + true, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *self.treasury.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + *self.payer.key, + true, + )); + remaining_accounts.iter().for_each(|remaining_account| { + accounts.push(solana_program::instruction::AccountMeta { + pubkey: *remaining_account.0.key, + is_signer: remaining_account.1, + is_writable: remaining_account.2, + }) + }); + let data = SetTreasuryInstructionData::new().try_to_vec().unwrap(); + + let instruction = solana_program::instruction::Instruction { + program_id: crate::BALANCE_PAYMENT_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(5 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.global_account.clone()); + account_infos.push(self.authority.clone()); + account_infos.push(self.treasury.clone()); + account_infos.push(self.payer.clone()); + remaining_accounts + .iter() + .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); + + if signers_seeds.is_empty() { + solana_program::program::invoke(&instruction, &account_infos) + } else { + solana_program::program::invoke_signed(&instruction, &account_infos, signers_seeds) + } + } +} + +/// Instruction builder for `SetTreasury` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[writable]` global_account +/// 1. `[signer]` authority +/// 2. `[]` treasury +/// 3. `[writable, signer]` payer +#[derive(Clone, Debug)] +pub struct SetTreasuryCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> SetTreasuryCpiBuilder<'a, 'b> { + pub fn new(program: &'b solana_program::account_info::AccountInfo<'a>) -> Self { + let instruction = Box::new(SetTreasuryCpiBuilderInstruction { + __program: program, + global_account: None, + authority: None, + treasury: None, + payer: None, + __remaining_accounts: Vec::new(), + }); + Self { instruction } + } + #[inline(always)] + pub fn global_account( + &mut self, + global_account: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.global_account = Some(global_account); + self + } + #[inline(always)] + pub fn authority( + &mut self, + authority: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.authority = Some(authority); + self + } + #[inline(always)] + pub fn treasury( + &mut self, + treasury: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.treasury = Some(treasury); + self + } + #[inline(always)] + pub fn payer(&mut self, payer: &'b solana_program::account_info::AccountInfo<'a>) -> &mut Self { + self.instruction.payer = Some(payer); + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: &'b solana_program::account_info::AccountInfo<'a>, + is_writable: bool, + is_signer: bool, + ) -> &mut Self { + self.instruction + .__remaining_accounts + .push((account, is_writable, is_signer)); + self + } + /// Add additional accounts to the instruction. + /// + /// Each account is represented by a tuple of the `AccountInfo`, a `bool` indicating whether the account is writable or not, + /// and a `bool` indicating whether the account is a signer or not. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> &mut Self { + self.instruction + .__remaining_accounts + .extend_from_slice(accounts); + self + } + #[inline(always)] + pub fn invoke(&self) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed(&[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed( + &self, + signers_seeds: &[&[&[u8]]], + ) -> solana_program::entrypoint::ProgramResult { + let instruction = SetTreasuryCpi { + __program: self.instruction.__program, + + global_account: self + .instruction + .global_account + .expect("global_account is not set"), + + authority: self.instruction.authority.expect("authority is not set"), + + treasury: self.instruction.treasury.expect("treasury is not set"), + + payer: self.instruction.payer.expect("payer is not set"), + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct SetTreasuryCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_program::account_info::AccountInfo<'a>, + global_account: Option<&'b solana_program::account_info::AccountInfo<'a>>, + authority: Option<&'b solana_program::account_info::AccountInfo<'a>>, + treasury: Option<&'b solana_program::account_info::AccountInfo<'a>>, + payer: Option<&'b solana_program::account_info::AccountInfo<'a>>, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )>, +} diff --git a/dephy-vending_machine-examples/balance-payment-sdk/src/generated/instructions/settle.rs b/dephy-vending_machine-examples/balance-payment-sdk/src/generated/instructions/settle.rs new file mode 100644 index 0000000..7839d3b --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment-sdk/src/generated/instructions/settle.rs @@ -0,0 +1,645 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +/// Accounts. +pub struct Settle { + pub global_account: solana_program::pubkey::Pubkey, + + pub user_account: solana_program::pubkey::Pubkey, + + pub user: solana_program::pubkey::Pubkey, + + pub treasury: solana_program::pubkey::Pubkey, + + pub lock_account: solana_program::pubkey::Pubkey, + + pub vault: solana_program::pubkey::Pubkey, + + pub bot: solana_program::pubkey::Pubkey, + + pub payer: solana_program::pubkey::Pubkey, + + pub system_program: solana_program::pubkey::Pubkey, +} + +impl Settle { + pub fn instruction( + &self, + args: SettleInstructionArgs, + ) -> solana_program::instruction::Instruction { + self.instruction_with_remaining_accounts(args, &[]) + } + #[allow(clippy::vec_init_then_push)] + pub fn instruction_with_remaining_accounts( + &self, + args: SettleInstructionArgs, + remaining_accounts: &[solana_program::instruction::AccountMeta], + ) -> solana_program::instruction::Instruction { + let mut accounts = Vec::with_capacity(9 + remaining_accounts.len()); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + self.global_account, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + self.user_account, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + self.user, false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + self.treasury, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + self.lock_account, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + self.vault, false, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + self.bot, true, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + self.payer, true, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + self.system_program, + false, + )); + accounts.extend_from_slice(remaining_accounts); + let mut data = SettleInstructionData::new().try_to_vec().unwrap(); + let mut args = args.try_to_vec().unwrap(); + data.append(&mut args); + + solana_program::instruction::Instruction { + program_id: crate::BALANCE_PAYMENT_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct SettleInstructionData { + discriminator: [u8; 8], +} + +impl SettleInstructionData { + pub fn new() -> Self { + Self { + discriminator: [175, 42, 185, 87, 144, 131, 102, 212], + } + } +} + +impl Default for SettleInstructionData { + fn default() -> Self { + Self::new() + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct SettleInstructionArgs { + pub nonce: u64, + pub amount_to_transfer: u64, +} + +/// Instruction builder for `Settle`. +/// +/// ### Accounts: +/// +/// 0. `[]` global_account +/// 1. `[writable]` user_account +/// 2. `[writable]` user +/// 3. `[writable]` treasury +/// 4. `[writable]` lock_account +/// 5. `[writable]` vault +/// 6. `[signer]` bot +/// 7. `[writable, signer]` payer +/// 8. `[optional]` system_program (default to `11111111111111111111111111111111`) +#[derive(Clone, Debug, Default)] +pub struct SettleBuilder { + global_account: Option, + user_account: Option, + user: Option, + treasury: Option, + lock_account: Option, + vault: Option, + bot: Option, + payer: Option, + system_program: Option, + nonce: Option, + amount_to_transfer: Option, + __remaining_accounts: Vec, +} + +impl SettleBuilder { + pub fn new() -> Self { + Self::default() + } + #[inline(always)] + pub fn global_account(&mut self, global_account: solana_program::pubkey::Pubkey) -> &mut Self { + self.global_account = Some(global_account); + self + } + #[inline(always)] + pub fn user_account(&mut self, user_account: solana_program::pubkey::Pubkey) -> &mut Self { + self.user_account = Some(user_account); + self + } + #[inline(always)] + pub fn user(&mut self, user: solana_program::pubkey::Pubkey) -> &mut Self { + self.user = Some(user); + self + } + #[inline(always)] + pub fn treasury(&mut self, treasury: solana_program::pubkey::Pubkey) -> &mut Self { + self.treasury = Some(treasury); + self + } + #[inline(always)] + pub fn lock_account(&mut self, lock_account: solana_program::pubkey::Pubkey) -> &mut Self { + self.lock_account = Some(lock_account); + self + } + #[inline(always)] + pub fn vault(&mut self, vault: solana_program::pubkey::Pubkey) -> &mut Self { + self.vault = Some(vault); + self + } + #[inline(always)] + pub fn bot(&mut self, bot: solana_program::pubkey::Pubkey) -> &mut Self { + self.bot = Some(bot); + self + } + #[inline(always)] + pub fn payer(&mut self, payer: solana_program::pubkey::Pubkey) -> &mut Self { + self.payer = Some(payer); + self + } + /// `[optional account, default to '11111111111111111111111111111111']` + #[inline(always)] + pub fn system_program(&mut self, system_program: solana_program::pubkey::Pubkey) -> &mut Self { + self.system_program = Some(system_program); + self + } + #[inline(always)] + pub fn nonce(&mut self, nonce: u64) -> &mut Self { + self.nonce = Some(nonce); + self + } + #[inline(always)] + pub fn amount_to_transfer(&mut self, amount_to_transfer: u64) -> &mut Self { + self.amount_to_transfer = Some(amount_to_transfer); + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: solana_program::instruction::AccountMeta, + ) -> &mut Self { + self.__remaining_accounts.push(account); + self + } + /// Add additional accounts to the instruction. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[solana_program::instruction::AccountMeta], + ) -> &mut Self { + self.__remaining_accounts.extend_from_slice(accounts); + self + } + #[allow(clippy::clone_on_copy)] + pub fn instruction(&self) -> solana_program::instruction::Instruction { + let accounts = Settle { + global_account: self.global_account.expect("global_account is not set"), + user_account: self.user_account.expect("user_account is not set"), + user: self.user.expect("user is not set"), + treasury: self.treasury.expect("treasury is not set"), + lock_account: self.lock_account.expect("lock_account is not set"), + vault: self.vault.expect("vault is not set"), + bot: self.bot.expect("bot is not set"), + payer: self.payer.expect("payer is not set"), + system_program: self + .system_program + .unwrap_or(solana_program::pubkey!("11111111111111111111111111111111")), + }; + let args = SettleInstructionArgs { + nonce: self.nonce.clone().expect("nonce is not set"), + amount_to_transfer: self + .amount_to_transfer + .clone() + .expect("amount_to_transfer is not set"), + }; + + accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) + } +} + +/// `settle` CPI accounts. +pub struct SettleCpiAccounts<'a, 'b> { + pub global_account: &'b solana_program::account_info::AccountInfo<'a>, + + pub user_account: &'b solana_program::account_info::AccountInfo<'a>, + + pub user: &'b solana_program::account_info::AccountInfo<'a>, + + pub treasury: &'b solana_program::account_info::AccountInfo<'a>, + + pub lock_account: &'b solana_program::account_info::AccountInfo<'a>, + + pub vault: &'b solana_program::account_info::AccountInfo<'a>, + + pub bot: &'b solana_program::account_info::AccountInfo<'a>, + + pub payer: &'b solana_program::account_info::AccountInfo<'a>, + + pub system_program: &'b solana_program::account_info::AccountInfo<'a>, +} + +/// `settle` CPI instruction. +pub struct SettleCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_program::account_info::AccountInfo<'a>, + + pub global_account: &'b solana_program::account_info::AccountInfo<'a>, + + pub user_account: &'b solana_program::account_info::AccountInfo<'a>, + + pub user: &'b solana_program::account_info::AccountInfo<'a>, + + pub treasury: &'b solana_program::account_info::AccountInfo<'a>, + + pub lock_account: &'b solana_program::account_info::AccountInfo<'a>, + + pub vault: &'b solana_program::account_info::AccountInfo<'a>, + + pub bot: &'b solana_program::account_info::AccountInfo<'a>, + + pub payer: &'b solana_program::account_info::AccountInfo<'a>, + + pub system_program: &'b solana_program::account_info::AccountInfo<'a>, + /// The arguments for the instruction. + pub __args: SettleInstructionArgs, +} + +impl<'a, 'b> SettleCpi<'a, 'b> { + pub fn new( + program: &'b solana_program::account_info::AccountInfo<'a>, + accounts: SettleCpiAccounts<'a, 'b>, + args: SettleInstructionArgs, + ) -> Self { + Self { + __program: program, + global_account: accounts.global_account, + user_account: accounts.user_account, + user: accounts.user, + treasury: accounts.treasury, + lock_account: accounts.lock_account, + vault: accounts.vault, + bot: accounts.bot, + payer: accounts.payer, + system_program: accounts.system_program, + __args: args, + } + } + #[inline(always)] + pub fn invoke(&self) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], &[]) + } + #[inline(always)] + pub fn invoke_with_remaining_accounts( + &self, + remaining_accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], remaining_accounts) + } + #[inline(always)] + pub fn invoke_signed( + &self, + signers_seeds: &[&[&[u8]]], + ) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(signers_seeds, &[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed_with_remaining_accounts( + &self, + signers_seeds: &[&[&[u8]]], + remaining_accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> solana_program::entrypoint::ProgramResult { + let mut accounts = Vec::with_capacity(9 + remaining_accounts.len()); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *self.global_account.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + *self.user_account.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + *self.user.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + *self.treasury.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + *self.lock_account.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + *self.vault.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *self.bot.key, + true, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + *self.payer.key, + true, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *self.system_program.key, + false, + )); + remaining_accounts.iter().for_each(|remaining_account| { + accounts.push(solana_program::instruction::AccountMeta { + pubkey: *remaining_account.0.key, + is_signer: remaining_account.1, + is_writable: remaining_account.2, + }) + }); + let mut data = SettleInstructionData::new().try_to_vec().unwrap(); + let mut args = self.__args.try_to_vec().unwrap(); + data.append(&mut args); + + let instruction = solana_program::instruction::Instruction { + program_id: crate::BALANCE_PAYMENT_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(10 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.global_account.clone()); + account_infos.push(self.user_account.clone()); + account_infos.push(self.user.clone()); + account_infos.push(self.treasury.clone()); + account_infos.push(self.lock_account.clone()); + account_infos.push(self.vault.clone()); + account_infos.push(self.bot.clone()); + account_infos.push(self.payer.clone()); + account_infos.push(self.system_program.clone()); + remaining_accounts + .iter() + .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); + + if signers_seeds.is_empty() { + solana_program::program::invoke(&instruction, &account_infos) + } else { + solana_program::program::invoke_signed(&instruction, &account_infos, signers_seeds) + } + } +} + +/// Instruction builder for `Settle` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[]` global_account +/// 1. `[writable]` user_account +/// 2. `[writable]` user +/// 3. `[writable]` treasury +/// 4. `[writable]` lock_account +/// 5. `[writable]` vault +/// 6. `[signer]` bot +/// 7. `[writable, signer]` payer +/// 8. `[]` system_program +#[derive(Clone, Debug)] +pub struct SettleCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> SettleCpiBuilder<'a, 'b> { + pub fn new(program: &'b solana_program::account_info::AccountInfo<'a>) -> Self { + let instruction = Box::new(SettleCpiBuilderInstruction { + __program: program, + global_account: None, + user_account: None, + user: None, + treasury: None, + lock_account: None, + vault: None, + bot: None, + payer: None, + system_program: None, + nonce: None, + amount_to_transfer: None, + __remaining_accounts: Vec::new(), + }); + Self { instruction } + } + #[inline(always)] + pub fn global_account( + &mut self, + global_account: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.global_account = Some(global_account); + self + } + #[inline(always)] + pub fn user_account( + &mut self, + user_account: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.user_account = Some(user_account); + self + } + #[inline(always)] + pub fn user(&mut self, user: &'b solana_program::account_info::AccountInfo<'a>) -> &mut Self { + self.instruction.user = Some(user); + self + } + #[inline(always)] + pub fn treasury( + &mut self, + treasury: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.treasury = Some(treasury); + self + } + #[inline(always)] + pub fn lock_account( + &mut self, + lock_account: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.lock_account = Some(lock_account); + self + } + #[inline(always)] + pub fn vault(&mut self, vault: &'b solana_program::account_info::AccountInfo<'a>) -> &mut Self { + self.instruction.vault = Some(vault); + self + } + #[inline(always)] + pub fn bot(&mut self, bot: &'b solana_program::account_info::AccountInfo<'a>) -> &mut Self { + self.instruction.bot = Some(bot); + self + } + #[inline(always)] + pub fn payer(&mut self, payer: &'b solana_program::account_info::AccountInfo<'a>) -> &mut Self { + self.instruction.payer = Some(payer); + self + } + #[inline(always)] + pub fn system_program( + &mut self, + system_program: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.system_program = Some(system_program); + self + } + #[inline(always)] + pub fn nonce(&mut self, nonce: u64) -> &mut Self { + self.instruction.nonce = Some(nonce); + self + } + #[inline(always)] + pub fn amount_to_transfer(&mut self, amount_to_transfer: u64) -> &mut Self { + self.instruction.amount_to_transfer = Some(amount_to_transfer); + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: &'b solana_program::account_info::AccountInfo<'a>, + is_writable: bool, + is_signer: bool, + ) -> &mut Self { + self.instruction + .__remaining_accounts + .push((account, is_writable, is_signer)); + self + } + /// Add additional accounts to the instruction. + /// + /// Each account is represented by a tuple of the `AccountInfo`, a `bool` indicating whether the account is writable or not, + /// and a `bool` indicating whether the account is a signer or not. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> &mut Self { + self.instruction + .__remaining_accounts + .extend_from_slice(accounts); + self + } + #[inline(always)] + pub fn invoke(&self) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed(&[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed( + &self, + signers_seeds: &[&[&[u8]]], + ) -> solana_program::entrypoint::ProgramResult { + let args = SettleInstructionArgs { + nonce: self.instruction.nonce.clone().expect("nonce is not set"), + amount_to_transfer: self + .instruction + .amount_to_transfer + .clone() + .expect("amount_to_transfer is not set"), + }; + let instruction = SettleCpi { + __program: self.instruction.__program, + + global_account: self + .instruction + .global_account + .expect("global_account is not set"), + + user_account: self + .instruction + .user_account + .expect("user_account is not set"), + + user: self.instruction.user.expect("user is not set"), + + treasury: self.instruction.treasury.expect("treasury is not set"), + + lock_account: self + .instruction + .lock_account + .expect("lock_account is not set"), + + vault: self.instruction.vault.expect("vault is not set"), + + bot: self.instruction.bot.expect("bot is not set"), + + payer: self.instruction.payer.expect("payer is not set"), + + system_program: self + .instruction + .system_program + .expect("system_program is not set"), + __args: args, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct SettleCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_program::account_info::AccountInfo<'a>, + global_account: Option<&'b solana_program::account_info::AccountInfo<'a>>, + user_account: Option<&'b solana_program::account_info::AccountInfo<'a>>, + user: Option<&'b solana_program::account_info::AccountInfo<'a>>, + treasury: Option<&'b solana_program::account_info::AccountInfo<'a>>, + lock_account: Option<&'b solana_program::account_info::AccountInfo<'a>>, + vault: Option<&'b solana_program::account_info::AccountInfo<'a>>, + bot: Option<&'b solana_program::account_info::AccountInfo<'a>>, + payer: Option<&'b solana_program::account_info::AccountInfo<'a>>, + system_program: Option<&'b solana_program::account_info::AccountInfo<'a>>, + nonce: Option, + amount_to_transfer: Option, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )>, +} diff --git a/dephy-vending_machine-examples/balance-payment-sdk/src/generated/instructions/withdraw.rs b/dephy-vending_machine-examples/balance-payment-sdk/src/generated/instructions/withdraw.rs new file mode 100644 index 0000000..011b156 --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment-sdk/src/generated/instructions/withdraw.rs @@ -0,0 +1,472 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +/// Accounts. +pub struct Withdraw { + pub user_account: solana_program::pubkey::Pubkey, + + pub user: solana_program::pubkey::Pubkey, + + pub vault: solana_program::pubkey::Pubkey, + + pub payer: solana_program::pubkey::Pubkey, + + pub system_program: solana_program::pubkey::Pubkey, +} + +impl Withdraw { + pub fn instruction( + &self, + args: WithdrawInstructionArgs, + ) -> solana_program::instruction::Instruction { + self.instruction_with_remaining_accounts(args, &[]) + } + #[allow(clippy::vec_init_then_push)] + pub fn instruction_with_remaining_accounts( + &self, + args: WithdrawInstructionArgs, + remaining_accounts: &[solana_program::instruction::AccountMeta], + ) -> solana_program::instruction::Instruction { + let mut accounts = Vec::with_capacity(5 + remaining_accounts.len()); + accounts.push(solana_program::instruction::AccountMeta::new( + self.user_account, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + self.user, true, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + self.vault, false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + self.payer, true, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + self.system_program, + false, + )); + accounts.extend_from_slice(remaining_accounts); + let mut data = WithdrawInstructionData::new().try_to_vec().unwrap(); + let mut args = args.try_to_vec().unwrap(); + data.append(&mut args); + + solana_program::instruction::Instruction { + program_id: crate::BALANCE_PAYMENT_ID, + accounts, + data, + } + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct WithdrawInstructionData { + discriminator: [u8; 8], +} + +impl WithdrawInstructionData { + pub fn new() -> Self { + Self { + discriminator: [183, 18, 70, 156, 148, 109, 161, 34], + } + } +} + +impl Default for WithdrawInstructionData { + fn default() -> Self { + Self::new() + } +} + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct WithdrawInstructionArgs { + pub amount: u64, +} + +/// Instruction builder for `Withdraw`. +/// +/// ### Accounts: +/// +/// 0. `[writable]` user_account +/// 1. `[writable, signer]` user +/// 2. `[writable]` vault +/// 3. `[writable, signer]` payer +/// 4. `[optional]` system_program (default to `11111111111111111111111111111111`) +#[derive(Clone, Debug, Default)] +pub struct WithdrawBuilder { + user_account: Option, + user: Option, + vault: Option, + payer: Option, + system_program: Option, + amount: Option, + __remaining_accounts: Vec, +} + +impl WithdrawBuilder { + pub fn new() -> Self { + Self::default() + } + #[inline(always)] + pub fn user_account(&mut self, user_account: solana_program::pubkey::Pubkey) -> &mut Self { + self.user_account = Some(user_account); + self + } + #[inline(always)] + pub fn user(&mut self, user: solana_program::pubkey::Pubkey) -> &mut Self { + self.user = Some(user); + self + } + #[inline(always)] + pub fn vault(&mut self, vault: solana_program::pubkey::Pubkey) -> &mut Self { + self.vault = Some(vault); + self + } + #[inline(always)] + pub fn payer(&mut self, payer: solana_program::pubkey::Pubkey) -> &mut Self { + self.payer = Some(payer); + self + } + /// `[optional account, default to '11111111111111111111111111111111']` + #[inline(always)] + pub fn system_program(&mut self, system_program: solana_program::pubkey::Pubkey) -> &mut Self { + self.system_program = Some(system_program); + self + } + #[inline(always)] + pub fn amount(&mut self, amount: u64) -> &mut Self { + self.amount = Some(amount); + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: solana_program::instruction::AccountMeta, + ) -> &mut Self { + self.__remaining_accounts.push(account); + self + } + /// Add additional accounts to the instruction. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[solana_program::instruction::AccountMeta], + ) -> &mut Self { + self.__remaining_accounts.extend_from_slice(accounts); + self + } + #[allow(clippy::clone_on_copy)] + pub fn instruction(&self) -> solana_program::instruction::Instruction { + let accounts = Withdraw { + user_account: self.user_account.expect("user_account is not set"), + user: self.user.expect("user is not set"), + vault: self.vault.expect("vault is not set"), + payer: self.payer.expect("payer is not set"), + system_program: self + .system_program + .unwrap_or(solana_program::pubkey!("11111111111111111111111111111111")), + }; + let args = WithdrawInstructionArgs { + amount: self.amount.clone().expect("amount is not set"), + }; + + accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) + } +} + +/// `withdraw` CPI accounts. +pub struct WithdrawCpiAccounts<'a, 'b> { + pub user_account: &'b solana_program::account_info::AccountInfo<'a>, + + pub user: &'b solana_program::account_info::AccountInfo<'a>, + + pub vault: &'b solana_program::account_info::AccountInfo<'a>, + + pub payer: &'b solana_program::account_info::AccountInfo<'a>, + + pub system_program: &'b solana_program::account_info::AccountInfo<'a>, +} + +/// `withdraw` CPI instruction. +pub struct WithdrawCpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_program::account_info::AccountInfo<'a>, + + pub user_account: &'b solana_program::account_info::AccountInfo<'a>, + + pub user: &'b solana_program::account_info::AccountInfo<'a>, + + pub vault: &'b solana_program::account_info::AccountInfo<'a>, + + pub payer: &'b solana_program::account_info::AccountInfo<'a>, + + pub system_program: &'b solana_program::account_info::AccountInfo<'a>, + /// The arguments for the instruction. + pub __args: WithdrawInstructionArgs, +} + +impl<'a, 'b> WithdrawCpi<'a, 'b> { + pub fn new( + program: &'b solana_program::account_info::AccountInfo<'a>, + accounts: WithdrawCpiAccounts<'a, 'b>, + args: WithdrawInstructionArgs, + ) -> Self { + Self { + __program: program, + user_account: accounts.user_account, + user: accounts.user, + vault: accounts.vault, + payer: accounts.payer, + system_program: accounts.system_program, + __args: args, + } + } + #[inline(always)] + pub fn invoke(&self) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], &[]) + } + #[inline(always)] + pub fn invoke_with_remaining_accounts( + &self, + remaining_accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], remaining_accounts) + } + #[inline(always)] + pub fn invoke_signed( + &self, + signers_seeds: &[&[&[u8]]], + ) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(signers_seeds, &[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed_with_remaining_accounts( + &self, + signers_seeds: &[&[&[u8]]], + remaining_accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> solana_program::entrypoint::ProgramResult { + let mut accounts = Vec::with_capacity(5 + remaining_accounts.len()); + accounts.push(solana_program::instruction::AccountMeta::new( + *self.user_account.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + *self.user.key, + true, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + *self.vault.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + *self.payer.key, + true, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *self.system_program.key, + false, + )); + remaining_accounts.iter().for_each(|remaining_account| { + accounts.push(solana_program::instruction::AccountMeta { + pubkey: *remaining_account.0.key, + is_signer: remaining_account.1, + is_writable: remaining_account.2, + }) + }); + let mut data = WithdrawInstructionData::new().try_to_vec().unwrap(); + let mut args = self.__args.try_to_vec().unwrap(); + data.append(&mut args); + + let instruction = solana_program::instruction::Instruction { + program_id: crate::BALANCE_PAYMENT_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(6 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.user_account.clone()); + account_infos.push(self.user.clone()); + account_infos.push(self.vault.clone()); + account_infos.push(self.payer.clone()); + account_infos.push(self.system_program.clone()); + remaining_accounts + .iter() + .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); + + if signers_seeds.is_empty() { + solana_program::program::invoke(&instruction, &account_infos) + } else { + solana_program::program::invoke_signed(&instruction, &account_infos, signers_seeds) + } + } +} + +/// Instruction builder for `Withdraw` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[writable]` user_account +/// 1. `[writable, signer]` user +/// 2. `[writable]` vault +/// 3. `[writable, signer]` payer +/// 4. `[]` system_program +#[derive(Clone, Debug)] +pub struct WithdrawCpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> WithdrawCpiBuilder<'a, 'b> { + pub fn new(program: &'b solana_program::account_info::AccountInfo<'a>) -> Self { + let instruction = Box::new(WithdrawCpiBuilderInstruction { + __program: program, + user_account: None, + user: None, + vault: None, + payer: None, + system_program: None, + amount: None, + __remaining_accounts: Vec::new(), + }); + Self { instruction } + } + #[inline(always)] + pub fn user_account( + &mut self, + user_account: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.user_account = Some(user_account); + self + } + #[inline(always)] + pub fn user(&mut self, user: &'b solana_program::account_info::AccountInfo<'a>) -> &mut Self { + self.instruction.user = Some(user); + self + } + #[inline(always)] + pub fn vault(&mut self, vault: &'b solana_program::account_info::AccountInfo<'a>) -> &mut Self { + self.instruction.vault = Some(vault); + self + } + #[inline(always)] + pub fn payer(&mut self, payer: &'b solana_program::account_info::AccountInfo<'a>) -> &mut Self { + self.instruction.payer = Some(payer); + self + } + #[inline(always)] + pub fn system_program( + &mut self, + system_program: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.system_program = Some(system_program); + self + } + #[inline(always)] + pub fn amount(&mut self, amount: u64) -> &mut Self { + self.instruction.amount = Some(amount); + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: &'b solana_program::account_info::AccountInfo<'a>, + is_writable: bool, + is_signer: bool, + ) -> &mut Self { + self.instruction + .__remaining_accounts + .push((account, is_writable, is_signer)); + self + } + /// Add additional accounts to the instruction. + /// + /// Each account is represented by a tuple of the `AccountInfo`, a `bool` indicating whether the account is writable or not, + /// and a `bool` indicating whether the account is a signer or not. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> &mut Self { + self.instruction + .__remaining_accounts + .extend_from_slice(accounts); + self + } + #[inline(always)] + pub fn invoke(&self) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed(&[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed( + &self, + signers_seeds: &[&[&[u8]]], + ) -> solana_program::entrypoint::ProgramResult { + let args = WithdrawInstructionArgs { + amount: self.instruction.amount.clone().expect("amount is not set"), + }; + let instruction = WithdrawCpi { + __program: self.instruction.__program, + + user_account: self + .instruction + .user_account + .expect("user_account is not set"), + + user: self.instruction.user.expect("user is not set"), + + vault: self.instruction.vault.expect("vault is not set"), + + payer: self.instruction.payer.expect("payer is not set"), + + system_program: self + .instruction + .system_program + .expect("system_program is not set"), + __args: args, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +#[derive(Clone, Debug)] +struct WithdrawCpiBuilderInstruction<'a, 'b> { + __program: &'b solana_program::account_info::AccountInfo<'a>, + user_account: Option<&'b solana_program::account_info::AccountInfo<'a>>, + user: Option<&'b solana_program::account_info::AccountInfo<'a>>, + vault: Option<&'b solana_program::account_info::AccountInfo<'a>>, + payer: Option<&'b solana_program::account_info::AccountInfo<'a>>, + system_program: Option<&'b solana_program::account_info::AccountInfo<'a>>, + amount: Option, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )>, +} diff --git a/dephy-vending_machine-examples/balance-payment-sdk/src/generated/mod.rs b/dephy-vending_machine-examples/balance-payment-sdk/src/generated/mod.rs new file mode 100644 index 0000000..6050d86 --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment-sdk/src/generated/mod.rs @@ -0,0 +1,14 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +pub mod accounts; +pub mod errors; +pub mod instructions; +pub mod programs; +pub mod types; + +pub(crate) use programs::*; diff --git a/dephy-vending_machine-examples/balance-payment-sdk/src/generated/programs.rs b/dephy-vending_machine-examples/balance-payment-sdk/src/generated/programs.rs new file mode 100644 index 0000000..3d9abc8 --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment-sdk/src/generated/programs.rs @@ -0,0 +1,11 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use solana_program::{pubkey, pubkey::Pubkey}; + +/// `balance_payment` program ID. +pub const BALANCE_PAYMENT_ID: Pubkey = pubkey!("GguVKxU88NUe3GLtns7Uaa6a8Pjb9USKq3WD1rjZnPS9"); diff --git a/dephy-vending_machine-examples/balance-payment-sdk/src/generated/types/e_d25519_recover_info.rs b/dephy-vending_machine-examples/balance-payment-sdk/src/generated/types/e_d25519_recover_info.rs new file mode 100644 index 0000000..ebaa398 --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment-sdk/src/generated/types/e_d25519_recover_info.rs @@ -0,0 +1,19 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +use borsh::BorshDeserialize; +use borsh::BorshSerialize; + +#[derive(BorshSerialize, BorshDeserialize, Clone, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct ED25519RecoverInfo { + #[cfg_attr(feature = "serde", serde(with = "serde_with::As::"))] + pub signature: [u8; 64], + #[cfg_attr(feature = "serde", serde(with = "serde_with::As::"))] + pub payload: [u8; 64], + pub deadline: i64, +} diff --git a/dephy-vending_machine-examples/balance-payment-sdk/src/generated/types/mod.rs b/dephy-vending_machine-examples/balance-payment-sdk/src/generated/types/mod.rs new file mode 100644 index 0000000..1d11556 --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment-sdk/src/generated/types/mod.rs @@ -0,0 +1,10 @@ +//! This code was AUTOGENERATED using the codama library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun codama to update it. +//! +//! +//! + +pub(crate) mod r#e_d25519_recover_info; + +pub use self::r#e_d25519_recover_info::*; diff --git a/dephy-vending_machine-examples/balance-payment-sdk/src/lib.rs b/dephy-vending_machine-examples/balance-payment-sdk/src/lib.rs new file mode 100644 index 0000000..92979fb --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment-sdk/src/lib.rs @@ -0,0 +1,293 @@ +#[allow(clippy::all)] +#[allow(warnings, unused)] +#[rustfmt::skip] +mod generated; + +mod error; +mod verify; + +use std::time::Duration; +use std::time::SystemTime; +use std::time::UNIX_EPOCH; + +pub use error::Error; +use generated::accounts::GlobalAccount; +use generated::accounts::UserAccount; +use generated::instructions::Lock; +use generated::instructions::LockInstructionArgs; +use generated::instructions::Pay; +use generated::instructions::PayInstructionArgs; +use generated::instructions::Settle; +use generated::instructions::SettleInstructionArgs; +use generated::programs::BALANCE_PAYMENT_ID; +use generated::types::ED25519RecoverInfo; +use solana_client::nonblocking::rpc_client::RpcClient; +use solana_program::pubkey::Pubkey; +use solana_sdk::bs58; +use solana_sdk::commitment_config::CommitmentConfig; +use solana_sdk::keccak; +use solana_sdk::signature::Keypair; +use solana_sdk::signer::EncodableKey; +use solana_sdk::signer::Signer; +use solana_sdk::system_program; +use solana_sdk::transaction::Transaction; +use verify::verify_signature; + +const SIGN_MESSAGE_PREFIX: &[u8; 31] = b"DePHY vending machine/Example:\n"; + +fn get_client(url: &str) -> RpcClient { + let timeout = Duration::from_secs(10); + let commitment_config = CommitmentConfig::processed(); + let confirm_transaction_initial_timeout = Duration::from_secs(10); + RpcClient::new_with_timeouts_and_commitment( + url.to_string(), + timeout, + commitment_config, + confirm_transaction_initial_timeout, + ) +} + +pub async fn check_eligible( + rpc_url: &str, + user: &str, + nonce: u64, + amount: u64, + recover_info: &str, +) -> Result { + let user: Pubkey = user.parse()?; + let recover_info: ED25519RecoverInfo = serde_json::from_str(recover_info)?; + + let client = get_client(rpc_url); + + let user_account_pubkey = + Pubkey::find_program_address(&[b"USER", user.as_ref()], &BALANCE_PAYMENT_ID).0; + let user_account_data = client.get_account_data(&user_account_pubkey).await?; + let user_account = UserAccount::from_bytes(&user_account_data)?; + + // 0. check nonce + if user_account.nonce != nonce { + tracing::error!( + "Nonce mismatch: expected {}, got {}", + nonce, + user_account.nonce + ); + return Ok(false); + } + + // 1. concat message + let message = { + let mut data = recover_info.payload.to_vec(); + data.extend_from_slice(&user_account.nonce.to_le_bytes()); + data.extend_from_slice(&recover_info.deadline.to_le_bytes()); + data + }; + + // 2. calc message hash + let message_hash = { + let mut hasher = keccak::Hasher::default(); + hasher.hash(&message); + hasher.result().to_bytes() + }; + + // 3. generate digest + let digest = { + let mut data = SIGN_MESSAGE_PREFIX.to_vec(); + data.extend_from_slice(bs58::encode(&message_hash).into_string().as_bytes()); + data + }; + + // 4. verify signature + let valid = verify_signature(&user, &recover_info.signature, &digest) + .map_err(|e| { + tracing::error!("Signature verification failed: {:?}", e); + e + }) + .is_ok(); + + if !valid { + tracing::error!("Invalid signature"); + return Ok(false); + } + + // 5. check signature expiration + let current_timestamp = SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_secs() as i64; + + if current_timestamp >= recover_info.deadline { + tracing::error!("Signature expired: deadline {}", recover_info.deadline); + return Ok(false); + } + + // 6. check user vault balance + let vault_pubkey = + Pubkey::find_program_address(&[b"VAULT", user.as_ref()], &BALANCE_PAYMENT_ID).0; + let vault_balance = client.get_account(&vault_pubkey).await?.lamports; + + if vault_balance - user_account.locked_amount < amount { + tracing::error!( + "Insufficient funds: available {}, required {}", + vault_balance - user_account.locked_amount, + amount + ); + return Ok(false); + } + + tracing::info!("User is eligible"); + Ok(true) +} + +pub async fn lock( + rpc_url: &str, + keypair_path: &str, + user: &str, + amount: u64, + recover_info: &str, +) -> Result { + let user: Pubkey = user.parse()?; + let recover_info: ED25519RecoverInfo = serde_json::from_str(recover_info)?; + + let bot = Keypair::read_from_file(keypair_path).map_err(Error::KeypairReadFailed)?; + let payer = bot.insecure_clone(); + + let client = get_client(rpc_url); + + let user_account_pubkey = + Pubkey::find_program_address(&[b"USER", user.as_ref()], &BALANCE_PAYMENT_ID).0; + let user_account_data = client.get_account_data(&user_account_pubkey).await?; + let user_account = UserAccount::from_bytes(&user_account_data)?; + + let lock_instruction = Lock { + global_account: Pubkey::find_program_address(&[b"GLOBAL"], &BALANCE_PAYMENT_ID).0, + user_account: user_account_pubkey, + user, + lock_account: Pubkey::find_program_address( + &[b"LOCK", user.as_ref(), &user_account.nonce.to_le_bytes()], + &BALANCE_PAYMENT_ID, + ) + .0, + vault: Pubkey::find_program_address(&[b"VAULT", user.as_ref()], &BALANCE_PAYMENT_ID).0, + bot: bot.pubkey(), + payer: payer.pubkey(), + system_program: system_program::id(), + }; + + let latest_block = client.get_latest_blockhash().await?; + + let transaction = Transaction::new_signed_with_payer( + &[lock_instruction.instruction(LockInstructionArgs { + amount, + recover_info, + })], + Some(&payer.pubkey()), + &[&bot, &payer], + latest_block, + ); + + let signature = client.send_and_confirm_transaction(&transaction).await?; + + Ok(signature.to_string()) +} + +pub async fn settle( + rpc_url: &str, + keypair_path: &str, + user: &str, + nonce: u64, + amount_to_transfer: u64, +) -> Result { + let user: Pubkey = user.parse()?; + + let bot = Keypair::read_from_file(keypair_path).map_err(Error::KeypairReadFailed)?; + let payer = bot.insecure_clone(); + + let client = get_client(rpc_url); + + let global_account_pubkey = Pubkey::find_program_address(&[b"GLOBAL"], &BALANCE_PAYMENT_ID).0; + let global_account_data = client.get_account_data(&global_account_pubkey).await?; + let global_account: GlobalAccount = GlobalAccount::from_bytes(&global_account_data)?; + let treasury = global_account.treasury; + + let latest_block = client.get_latest_blockhash().await?; + + let settle_instruction = Settle { + global_account: global_account_pubkey, + user_account: Pubkey::find_program_address(&[b"USER", user.as_ref()], &BALANCE_PAYMENT_ID) + .0, + user, + treasury, + lock_account: Pubkey::find_program_address( + &[b"LOCK", user.as_ref(), &nonce.to_le_bytes()], + &BALANCE_PAYMENT_ID, + ) + .0, + vault: Pubkey::find_program_address(&[b"VAULT", user.as_ref()], &BALANCE_PAYMENT_ID).0, + bot: bot.pubkey(), + payer: payer.pubkey(), + system_program: system_program::id(), + }; + + let transaction = Transaction::new_signed_with_payer( + &[settle_instruction.instruction(SettleInstructionArgs { + nonce, + amount_to_transfer, + })], + Some(&payer.pubkey()), + &[&bot, &payer], + latest_block, + ); + + let signature = client.send_and_confirm_transaction(&transaction).await?; + + Ok(signature.to_string()) +} + +pub async fn pay( + rpc_url: &str, + keypair_path: &str, + user: &str, + amount_to_transfer: u64, + recover_info: &str, +) -> Result { + let user: Pubkey = user.parse()?; + let recover_info: ED25519RecoverInfo = serde_json::from_str(recover_info)?; + + let bot = Keypair::read_from_file(keypair_path).map_err(Error::KeypairReadFailed)?; + let payer = bot.insecure_clone(); + + let client = get_client(rpc_url); + + let global_account_pubkey = Pubkey::find_program_address(&[b"GLOBAL"], &BALANCE_PAYMENT_ID).0; + let global_account_data = client.get_account_data(&global_account_pubkey).await?; + let global_account: GlobalAccount = GlobalAccount::from_bytes(&global_account_data)?; + let treasury = global_account.treasury; + + let latest_block = client.get_latest_blockhash().await?; + + let pay_instruction = Pay { + global_account: global_account_pubkey, + user_account: Pubkey::find_program_address(&[b"USER", user.as_ref()], &BALANCE_PAYMENT_ID) + .0, + user, + treasury, + vault: Pubkey::find_program_address(&[b"VAULT", user.as_ref()], &BALANCE_PAYMENT_ID).0, + bot: bot.pubkey(), + payer: payer.pubkey(), + system_program: system_program::id(), + }; + + let transaction = Transaction::new_signed_with_payer( + &[pay_instruction.instruction(PayInstructionArgs { + amount_to_transfer, + recover_info, + })], + Some(&payer.pubkey()), + &[&bot, &payer], + latest_block, + ); + + let signature = client.send_and_confirm_transaction(&transaction).await?; + + Ok(signature.to_string()) +} diff --git a/dephy-vending_machine-examples/balance-payment-sdk/src/verify.rs b/dephy-vending_machine-examples/balance-payment-sdk/src/verify.rs new file mode 100644 index 0000000..453165e --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment-sdk/src/verify.rs @@ -0,0 +1,61 @@ +use arrayref::array_ref; +use curve25519_dalek::scalar::Scalar; +use sha2::Digest; +use solana_program::pubkey::Pubkey; +use solana_zk_token_sdk::curve25519::edwards::multiply_edwards; +use solana_zk_token_sdk::curve25519::edwards::subtract_edwards; +use solana_zk_token_sdk::curve25519::edwards::validate_edwards; +use solana_zk_token_sdk::curve25519::edwards::PodEdwardsPoint; +use solana_zk_token_sdk::curve25519::scalar::PodScalar; + +use crate::Error; + +// funny number +const EDWARDS_BASE_POINT: PodEdwardsPoint = PodEdwardsPoint([ + 0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, +]); + +pub fn verify_signature( + pubkey: &Pubkey, + signature: &[u8; 64], + message: &[u8], +) -> Result { + let a = PodEdwardsPoint(pubkey.to_bytes()); + let r = PodEdwardsPoint(*array_ref![signature, 0, 32]); + if !validate_edwards(&a) { + return Err(Error::SignatureVerificationFailed( + "Pubkey is not a valid EdwardsPoint".to_string(), + )); + } + if !validate_edwards(&r) { + return Err(Error::SignatureVerificationFailed( + "Signature R is not a valid EdwardsPoint".to_string(), + )); + } + + let s = array_ref![signature, 32, 32]; + let s_scalar = Scalar::from_bytes_mod_order(*s); + let s_scalar = PodScalar(s_scalar.to_bytes()); + + let mut hasher = sha2::Sha512::new(); + // R || A || M + hasher.update(r.0); + hasher.update(a.0); + hasher.update(message); + let hash_bytes = hasher.finalize(); + let hash_array = array_ref![hash_bytes, 0, 64]; + let h_scalar = Scalar::from_bytes_mod_order_wide(hash_array); + let h_scalar = PodScalar(h_scalar.to_bytes()); + + let s_b = multiply_edwards(&s_scalar, &EDWARDS_BASE_POINT).ok_or( + Error::SignatureVerificationFailed("Failed to multiply S*B".to_string()), + )?; + let h_a = multiply_edwards(&h_scalar, &a).ok_or(Error::SignatureVerificationFailed( + "Failed to multiply H*A".to_string(), + ))?; + let r_prime = subtract_edwards(&s_b, &h_a).ok_or(Error::SignatureVerificationFailed( + "Failed to subtract HA from SB".to_string(), + ))?; + Ok(r_prime == r) +} diff --git a/dephy-vending_machine-examples/balance-payment/Anchor.toml b/dephy-vending_machine-examples/balance-payment/Anchor.toml new file mode 100644 index 0000000..7eb2421 --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/Anchor.toml @@ -0,0 +1,19 @@ +[toolchain] + +[features] +resolution = true +skip-lint = false + +[programs.localnet] +balance_payment = "GguVKxU88NUe3GLtns7Uaa6a8Pjb9USKq3WD1rjZnPS9" + +[registry] +url = "https://api.apr.dev" + +[provider] +cluster = "Localnet" +wallet = "~/.config/solana/id.json" + +[scripts] +cli = "bun run -b scripts/cli.ts" +test = "bun run -b ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts" diff --git a/dephy-vending_machine-examples/balance-payment/Cargo.lock b/dephy-vending_machine-examples/balance-payment/Cargo.lock new file mode 100644 index 0000000..0afd5be --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/Cargo.lock @@ -0,0 +1,2126 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[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 = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "anchor-attribute-access-control" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37013051defd745a5437d6842bd404e5480e14ad4e4f0441dd9a81a4b9aea1d6" +dependencies = [ + "anchor-syn", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "anchor-attribute-account" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92db0f793e924e18462b3fac53c5759a8248649a8072788b5e88a4af714998c8" +dependencies = [ + "anchor-syn", + "bs58 0.5.1", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "anchor-attribute-constant" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a98126ebfc96d6248899caadc9ea7c2403420c4f5c994e541802bce9f423674" +dependencies = [ + "anchor-syn", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "anchor-attribute-error" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8a4dcb403f872fbcd0910fc39a3e05bb6c43a8399f915a1878e62eb680fbb23" +dependencies = [ + "anchor-syn", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "anchor-attribute-event" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "420d651b2703ccff86f6c4b7c394140cb85049787c078a5f8280506121d48065" +dependencies = [ + "anchor-syn", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "anchor-attribute-program" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d258f3a9f47db7f4199888df0ee67e42b960a7acb8f5c336b585d4eb243b9665" +dependencies = [ + "anchor-lang-idl", + "anchor-syn", + "anyhow", + "bs58 0.5.1", + "heck", + "proc-macro2", + "quote", + "serde_json", + "syn 1.0.109", +] + +[[package]] +name = "anchor-derive-accounts" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "097147501de51105d8dbdad9bd5a96a1b17ecbb2cee9f200d6167031372eab3b" +dependencies = [ + "anchor-syn", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "anchor-derive-serde" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5a24721da4ed67f0a1391cac27ea7e51c255cbd94cdcc6728a0aa56227628d0" +dependencies = [ + "anchor-syn", + "borsh-derive-internal", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "anchor-derive-space" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f41986f84d238a2f7a807f3a98da5df0e97ebe23f29f7d67b8cdd4fd80bc1ba1" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "anchor-lang" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eba81a0543fee1b7b610fe9ebedbae6a14e8d3e85a6a6dd48871d48a08880195" +dependencies = [ + "anchor-attribute-access-control", + "anchor-attribute-account", + "anchor-attribute-constant", + "anchor-attribute-error", + "anchor-attribute-event", + "anchor-attribute-program", + "anchor-derive-accounts", + "anchor-derive-serde", + "anchor-derive-space", + "anchor-lang-idl", + "base64 0.21.7", + "bincode", + "borsh 0.10.4", + "bytemuck", + "solana-program", + "thiserror", +] + +[[package]] +name = "anchor-lang-idl" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e8599d21995f68e296265aa5ab0c3cef582fd58afec014d01bd0bce18a4418" +dependencies = [ + "anchor-lang-idl-spec", + "anyhow", + "heck", + "regex", + "serde", + "serde_json", + "sha2 0.10.8", +] + +[[package]] +name = "anchor-lang-idl-spec" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bdf143115440fe621bdac3a29a1f7472e09f6cd82b2aa569429a0c13f103838" +dependencies = [ + "anyhow", + "serde", +] + +[[package]] +name = "anchor-syn" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "564685b759db12a2424d1b2688cfdf0fec26a023813bc461274754fb0e5d97b0" +dependencies = [ + "anyhow", + "bs58 0.5.1", + "cargo_toml", + "heck", + "proc-macro2", + "quote", + "serde", + "serde_json", + "sha2 0.10.8", + "syn 1.0.109", + "thiserror", +] + +[[package]] +name = "anyhow" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04" + +[[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", + "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", + "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", +] + +[[package]] +name = "ark-serialize-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-std" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand 0.8.5", +] + +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "balance-payment" +version = "0.1.0" +dependencies = [ + "anchor-lang", + "anyhow", + "arrayref", + "bs58 0.4.0", + "curve25519-dalek 4.1.3", + "sha2 0.10.8", + "solana-zk-token-sdk", +] + +[[package]] +name = "base64" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" + +[[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 = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bitflags" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" +dependencies = [ + "serde", +] + +[[package]] +name = "blake3" +version = "1.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8ee0c1824c4dea5b5f81736aff91bae041d2c07ee1192bec91054e10e3e601e" +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", +] + +[[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 = "block-padding" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" + +[[package]] +name = "borsh" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115e54d64eb62cdebad391c19efc9dce4981c690c85a33a12199d99bb9546fee" +dependencies = [ + "borsh-derive 0.10.4", + "hashbrown 0.13.2", +] + +[[package]] +name = "borsh" +version = "1.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5430e3be710b68d984d1391c854eb431a9d548640711faa54eecb1df93db91cc" +dependencies = [ + "borsh-derive 1.5.5", + "cfg_aliases", +] + +[[package]] +name = "borsh-derive" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "831213f80d9423998dd696e2c5345aba6be7a0bd8cd19e31c5243e13df1cef89" +dependencies = [ + "borsh-derive-internal", + "borsh-schema-derive-internal", + "proc-macro-crate 0.1.5", + "proc-macro2", + "syn 1.0.109", +] + +[[package]] +name = "borsh-derive" +version = "1.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8b668d39970baad5356d7c83a86fee3a539e6f93bf6764c97368243e17a0487" +dependencies = [ + "once_cell", + "proc-macro-crate 3.2.0", + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[package]] +name = "borsh-derive-internal" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65d6ba50644c98714aa2a70d13d7df3cd75cd2b523a2b452bf010443800976b3" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "borsh-schema-derive-internal" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "276691d96f063427be83e6692b86148e488ebba9f48f77788724ca027ba3b6d4" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "bs58" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" + +[[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.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[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 = "bytemuck" +version = "1.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef657dfab802224e671f5818e9a4935f9b1957ed18e58292690cc39e7a4092a3" + +[[package]] +name = "bytemuck_derive" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fa76293b4f7bb636ab88fd78228235b5248b4d05cc589aed610f954af5d7c7a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "cargo_toml" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a98356df42a2eb1bd8f1793ae4ee4de48e384dd974ce5eac8eee802edb7492be" +dependencies = [ + "serde", + "toml 0.8.19", +] + +[[package]] +name = "cc" +version = "1.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13208fcbb66eaeffe09b99fffbe1af420f00a7b35aa99ad683dfc1aa76145229" +dependencies = [ + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "chrono" +version = "0.4.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825" +dependencies = [ + "num-traits", +] + +[[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 = "console_error_panic_hook" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if", + "wasm-bindgen", +] + +[[package]] +name = "console_log" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89f72f65e8501878b8a004d5a1afb780987e2ce2b4532c562e367a72c57499f" +dependencies = [ + "log", + "web-sys", +] + +[[package]] +name = "constant_time_eq" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" + +[[package]] +name = "cpufeatures" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" +dependencies = [ + "libc", +] + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "typenum", +] + +[[package]] +name = "crypto-mac" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" +dependencies = [ + "generic-array", + "subtle", +] + +[[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 = "3.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90f9d052967f590a76e62eb387bd0bbb1b000182c3cefe5364db6b7211651bc0" +dependencies = [ + "byteorder", + "digest 0.9.0", + "rand_core 0.5.1", + "serde", + "subtle", + "zeroize", +] + +[[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", + "fiat-crypto", + "rustc_version", + "subtle", +] + +[[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.96", +] + +[[package]] +name = "darling" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.96", +] + +[[package]] +name = "darling_macro" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.96", +] + +[[package]] +name = "derivation-path" +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 = "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", + "crypto-common", + "subtle", +] + +[[package]] +name = "ed25519" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" +dependencies = [ + "signature", +] + +[[package]] +name = "ed25519-dalek" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" +dependencies = [ + "curve25519-dalek 3.2.1", + "ed25519", + "rand 0.7.3", + "serde", + "sha2 0.9.9", + "zeroize", +] + +[[package]] +name = "ed25519-dalek-bip32" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d2be62a4061b872c8c0873ee4fc6f101ce7b889d039f019c5fa2af471a59908" +dependencies = [ + "derivation-path", + "ed25519-dalek", + "hmac 0.12.1", + "sha2 0.10.8", +] + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "feature-probe" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835a3dc7d1ec9e75e2b5fb4ba75396837112d2060b03f7d43bc1897c7f7211da" + +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "serde", + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "wasm-bindgen", +] + +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash", +] + +[[package]] +name = "hashbrown" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" + +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[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 = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "indexmap" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" +dependencies = [ + "equivalent", + "hashbrown 0.15.2", +] + +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" + +[[package]] +name = "js-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "keccak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.169" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" + +[[package]] +name = "libsecp256k1" +version = "0.6.0" +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", +] + +[[package]] +name = "libsecp256k1-core" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0f6ab710cec28cef759c5f18671a27dae2a5f952cdaaee1d8e2908cb2478a80" +dependencies = [ + "crunchy", + "digest 0.9.0", + "subtle", +] + +[[package]] +name = "libsecp256k1-gen-ecmult" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccab96b584d38fac86a83f07e659f0deafd0253dc096dab5a36d53efe653c5c3" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "libsecp256k1-gen-genmult" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67abfe149395e3aa1c48a2beb32b068e2334402df8181f818d3aee2b304c4f5d" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58c38e2799fc0978b65dfff8023ec7843e2330bb462f19198840b34b6582397d" +dependencies = [ + "byteorder", + "keccak", + "rand_core 0.6.4", + "zeroize", +] + +[[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-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_enum" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" +dependencies = [ + "proc-macro-crate 3.2.0", + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[package]] +name = "once_cell" +version = "1.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" + +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "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 = "ppv-lite86" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro-crate" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" +dependencies = [ + "toml 0.5.11", +] + +[[package]] +name = "proc-macro-crate" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro2" +version = "1.0.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" +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 = "quote" +version = "1.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.7.3" +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", +] + +[[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_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", +] + +[[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_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.15", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "redox_syscall" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustversion" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "semver" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f79dfe2d285b0488816f30e700a7438c5a73d816b5b7d3ac72fbc48b0d185e03" + +[[package]] +name = "serde" +version = "1.0.217" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_bytes" +version = "0.11.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "387cc504cb06bb40a96c8e04e951fe01854cf6bc921053c954e4a606d9675c6a" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.217" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[package]] +name = "serde_json" +version = "1.0.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "930cfb6e6abf99298aaad7d29abbef7a9999a9a8806a40088f55f0dcec03146b" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_spanned" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +dependencies = [ + "serde", +] + +[[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", +] + +[[package]] +name = "serde_with_macros" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "881b6f881b17d13214e5d494c939ebab463d01264ce1811e9d4ac3a882e7695f" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +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", +] + +[[package]] +name = "sha3" +version = "0.9.1" +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", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest 0.10.7", + "keccak", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signature" +version = "1.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" + +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "solana-curve25519" +version = "2.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef53061d8df8e7672af6b7130a934d6004a677e8f18526dce55da8f952f2ed37" +dependencies = [ + "bytemuck", + "bytemuck_derive", + "curve25519-dalek 3.2.1", + "solana-program", + "thiserror", +] + +[[package]] +name = "solana-program" +version = "2.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd54adccd5d91cdfb71e3aeadb77d7b95db15857f0457c944e45794f1d547c9d" +dependencies = [ + "ark-bn254", + "ark-ec", + "ark-ff", + "ark-serialize", + "base64 0.22.1", + "bincode", + "bitflags", + "blake3", + "borsh 0.10.4", + "borsh 1.5.5", + "bs58 0.5.1", + "bv", + "bytemuck", + "bytemuck_derive", + "console_error_panic_hook", + "console_log", + "curve25519-dalek 3.2.1", + "getrandom 0.2.15", + "js-sys", + "lazy_static", + "libsecp256k1", + "log", + "memoffset", + "num-bigint", + "num-derive", + "num-traits", + "parking_lot", + "rand 0.8.5", + "rustc_version", + "rustversion", + "serde", + "serde_bytes", + "serde_derive", + "sha2 0.10.8", + "sha3 0.10.8", + "solana-sdk-macro", + "thiserror", + "wasm-bindgen", +] + +[[package]] +name = "solana-sdk" +version = "2.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaeeedba53edf184c58b22f9f0701f821fd5d9161423036e168bcb5b3d78d2b3" +dependencies = [ + "bincode", + "bitflags", + "borsh 1.5.5", + "bs58 0.5.1", + "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", + "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-program", + "solana-sdk-macro", + "thiserror", + "uriparse", + "wasm-bindgen", +] + +[[package]] +name = "solana-sdk-macro" +version = "2.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac2b11eb2ebad5e1dd244bd0058bb004d972e7b16834d7ff241c35e3fceda8ee" +dependencies = [ + "bs58 0.5.1", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.96", +] + +[[package]] +name = "solana-zk-token-sdk" +version = "2.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e6f619f88203c99438beefe0e1193da075d118961392055d7ef13f1d5cde40b" +dependencies = [ + "aes-gcm-siv", + "base64 0.22.1", + "bincode", + "bytemuck", + "bytemuck_derive", + "byteorder", + "curve25519-dalek 3.2.1", + "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", +] + +[[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.96" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5d0adab1ae378d7f53bdebc67a39f1f151407ef230f0ce2883572f5d8985c80" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl", +] + +[[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.96", +] + +[[package]] +name = "tinyvec" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "022db8904dfa342efe721985167e9fcd16c29b226db4397ed752a761cfce81e8" +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 = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + +[[package]] +name = "toml" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicode-ident" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" + +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + +[[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 = "uriparse" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0200d0fc04d809396c2ad43f3c95da3582a2556eba8d453c1087f4120ee352ff" +dependencies = [ + "fnv", + "lazy_static", +] + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" +dependencies = [ + "bumpalo", + "log", + "proc-macro2", + "quote", + "syn 2.0.96", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-sys" +version = "0.3.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[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_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[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_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[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_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winnow" +version = "0.6.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8d71a593cc5c42ad7876e2c1fda56f314f3754c084128833e64f1345ff8a03a" +dependencies = [ + "memchr", +] + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] + +[[package]] +name = "zeroize" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.96", +] diff --git a/dephy-vending_machine-examples/balance-payment/Cargo.toml b/dephy-vending_machine-examples/balance-payment/Cargo.toml new file mode 100644 index 0000000..68da9dd --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/Cargo.toml @@ -0,0 +1,13 @@ +[workspace] +members = ["programs/*"] +resolver = "2" + +[profile.release] +overflow-checks = true +lto = "fat" +codegen-units = 1 + +[profile.release.build-override] +opt-level = 3 +incremental = false +codegen-units = 1 diff --git a/dephy-vending_machine-examples/balance-payment/README.md b/dephy-vending_machine-examples/balance-payment/README.md new file mode 100644 index 0000000..ceb2a95 --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/README.md @@ -0,0 +1,96 @@ +# Balance Payment Program + +This project is a Solana program built using the Anchor framework. +It allows users to deposit, withdraw, lock, and settle funds, as well as make payments to a treasury account. +The program is designed to be used in conjunction with a bot and a treasury account, which are managed by an authority. + +## Getting Started + +### Prerequisites + +Before you begin, ensure you have the following installed: + +- [Node.js](https://nodejs.org) (v20 or higher) +- [Bun](https://bun.sh/docs/installation) +- [Solana & Anchor](https://solana.com/docs/intro/installation) + +### Installation + +```bash +bun install +``` + +## Compiling the Program + +To compile the program, run: + +```bash +anchor build +``` + +This command compiles the Solana program and generates the necessary artifacts. + +## Deploying the Program Locally + +To deploy the program to a local Solana validator, follow these steps: + +1. **Start a local Solana validator:** + +```bash +solana-test-validator --reset +``` + +This command starts a local Solana blockchain instance. + +2. **Ensure your Solana CLI is configured to use the local validator:** + +```bash +solana config set --url http://localhost:8899 +``` + +3. **Airdrop SOL to your local wallet:** + +```bash +solana airdrop 2 +solana airdrop 2 9nyhqLqmbWoUuNXA1XCVnEqiS9UWvxFYa1yynVVFzR4D +``` + +4. **Deploy the program to the local validator:** + +```bash +solana program deploy ./target/deploy/balance_payment.so --program-id ./programs/balance-payment/keypair.json +``` + +This command will deploy the program to the local Solana validator and output the program ID. + +# Initialize the Program + +Initializes the program with an authority, treasury, and bot. + +```bash +anchor run cli -- initialize --authority --treasury --bot 9nyhqLqmbWoUuNXA1XCVnEqiS9UWvxFYa1yynVVFzR4D +``` + +- `--authority`: The public key of the authority. +- `--treasury`: The public key of the treasury account. +- `--bot`: The public key of the bot account. + +# App Demo + +The `app` folder contains a demo application that interacts with the Balance Payment program. To run the demo: + +- Navigate to the `app` directory: +```bash +cd app +``` +- Install dependencies: +```bash +bun install +``` +- Start the development server: +```bash +bun run dev +``` +- Open your browser and navigate to `http://localhost:5173` to view the demo. + +This demo provides a user-friendly interface to interact with the Balance Payment program, enabling users to manage funds and simulate charging sessions. diff --git a/dephy-vending_machine-examples/balance-payment/app/.env.example b/dephy-vending_machine-examples/balance-payment/app/.env.example new file mode 100644 index 0000000..600ff62 --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/app/.env.example @@ -0,0 +1,2 @@ +VITE_RELAY_ENDPOINT= +VITE_NETWORK= diff --git a/dephy-vending_machine-examples/balance-payment/app/.gitignore b/dephy-vending_machine-examples/balance-payment/app/.gitignore new file mode 100644 index 0000000..33c24ce --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/app/.gitignore @@ -0,0 +1,25 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? +/tmp diff --git a/dephy-vending_machine-examples/balance-payment/app/.prettierignore b/dephy-vending_machine-examples/balance-payment/app/.prettierignore new file mode 100644 index 0000000..8d646b0 --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/app/.prettierignore @@ -0,0 +1,8 @@ +# Add files here to ignore them from prettier formatting +/.yarn +/coverage +/dist +/tmp +package-lock.json +pnpm-lock.yaml +yarn.lock diff --git a/dephy-vending_machine-examples/balance-payment/app/.prettierrc b/dephy-vending_machine-examples/balance-payment/app/.prettierrc new file mode 100644 index 0000000..f8fb56b --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/app/.prettierrc @@ -0,0 +1,7 @@ +{ + "singleQuote": true, + "printWidth": 120, + "semi": false, + "trailingComma": "all", + "arrowParens": "always" +} diff --git a/dephy-vending_machine-examples/balance-payment/app/LICENSE b/dephy-vending_machine-examples/balance-payment/app/LICENSE new file mode 100644 index 0000000..f79b9ea --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/app/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022-2024 Solana Foundation + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/dephy-vending_machine-examples/balance-payment/app/README.md b/dephy-vending_machine-examples/balance-payment/app/README.md new file mode 100644 index 0000000..7726ada --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/app/README.md @@ -0,0 +1,7 @@ +Balance payment dApp +==== + +## Run + +- `bun i` +- `bun run dev` diff --git a/dephy-vending_machine-examples/balance-payment/app/eslint.config.js b/dephy-vending_machine-examples/balance-payment/app/eslint.config.js new file mode 100644 index 0000000..05c6758 --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/app/eslint.config.js @@ -0,0 +1,25 @@ +import js from '@eslint/js' +import globals from 'globals' +import reactHooks from 'eslint-plugin-react-hooks' +import reactRefresh from 'eslint-plugin-react-refresh' +import tseslint from 'typescript-eslint' + +export default tseslint.config( + { ignores: ['dist'] }, + { + extends: [js.configs.recommended, ...tseslint.configs.recommended], + files: ['**/*.{ts,tsx}'], + languageOptions: { + ecmaVersion: 2020, + globals: globals.browser, + }, + plugins: { + 'react-hooks': reactHooks, + 'react-refresh': reactRefresh, + }, + rules: { + ...reactHooks.configs.recommended.rules, + 'react-refresh/only-export-components': ['warn', { allowConstantExport: true }], + }, + }, +) diff --git a/dephy-vending_machine-examples/balance-payment/app/index.html b/dephy-vending_machine-examples/balance-payment/app/index.html new file mode 100644 index 0000000..a5f3d4e --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/app/index.html @@ -0,0 +1,13 @@ + + + + + + + Balance Payment + + +
+ + + diff --git a/dephy-vending_machine-examples/balance-payment/app/package.json b/dephy-vending_machine-examples/balance-payment/app/package.json new file mode 100644 index 0000000..09f76de --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/app/package.json @@ -0,0 +1,58 @@ +{ + "name": "template-react-vite-tailwind-counter", + "description": "React + Vite + Tailwind + Anchor Counter program", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc -b && vite build", + "lint": "eslint .", + "preview": "vite preview" + }, + "dependencies": { + "@coral-xyz/anchor": "^0.31.0", + "@noble/hashes": "^1.7.0", + "@solana/spl-token": "^0.4.8", + "@solana/wallet-adapter-base": "^0.9.23", + "@solana/wallet-adapter-react": "^0.15.35", + "@solana/wallet-adapter-react-ui": "^0.9.35", + "@solana/web3.js": "^1.95.3", + "@tabler/icons-react": "^3.15.0", + "@tanstack/react-query": "^5.55.2", + "bs58": "^6.0.0", + "daisyui": "^4.12.10", + "jotai": "^2.9.3", + "keccak": "^3.0.4", + "node-stdlib-browser": "^1.2.0", + "nostr-tools": "^2.10.4", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-hot-toast": "^2.4.1", + "react-router": "^6.26.1", + "react-router-dom": "^6.26.1", + "tailwindcss": "^3.4.10", + "uuid": "^11.0.5" + }, + "devDependencies": { + "@esbuild-plugins/node-globals-polyfill": "^0.2.3", + "@eslint/js": "^9.9.0", + "@types/jest": "^29.5.13", + "@types/keccak": "^3.0.5", + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", + "@vitejs/plugin-react": "^4.3.1", + "eslint": "^9.9.0", + "eslint-plugin-react-hooks": "^5.1.0-rc.0", + "eslint-plugin-react-refresh": "^0.4.9", + "globals": "^15.9.0", + "jest": "^29.7.0", + "prettier": "^3.3.3", + "ts-jest": "^29.2.5", + "typescript": "^5.5.3", + "typescript-eslint": "^8.0.1", + "vite": "^5.4.1", + "vite-plugin-node-polyfills": "^0.22.0", + "vite-tsconfig-paths": "^5.0.1" + } +} diff --git a/dephy-vending_machine-examples/balance-payment/app/postcss.config.mjs b/dephy-vending_machine-examples/balance-payment/app/postcss.config.mjs new file mode 100644 index 0000000..0dc456a --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/app/postcss.config.mjs @@ -0,0 +1,8 @@ +/** @type {import('postcss-load-config').Config} */ +const config = { + plugins: { + tailwindcss: {}, + }, +} + +export default config diff --git a/dephy-vending_machine-examples/balance-payment/app/public/logo.png b/dephy-vending_machine-examples/balance-payment/app/public/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..404e2880d414c16d86ce1dcd418c7f6b1e092d94 GIT binary patch literal 12306 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 z%0D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 q-T#~Q><;*! import('../components/account/account-list-feature')) +const AccountDetailFeature = lazy(() => import('../components/account/account-detail-feature')) +const ClusterFeature = lazy(() => import('../components/cluster/cluster-feature')) +const BalancePaymentFeature = lazy(() => import('../components/balance-payment/balance-payment-feature')) +const DashboardFeature = lazy(() => import('../components/dashboard/dashboard-feature')) + +const links: { label: string; path: string }[] = [ + { label: 'Account', path: '/account' }, + { label: 'Clusters', path: '/clusters' }, + { label: 'Balance Payment Program', path: '/program' }, +] + +const routes: RouteObject[] = [ + { path: '/account/', element: }, + { path: '/account/:address', element: }, + { path: '/program', element: }, + { path: '/clusters', element: }, +] + +export function AppRoutes() { + const router = useRoutes([ + { index: true, element: }, + { path: '/dashboard', element: }, + ...routes, + { path: '*', element: }, + ]) + return {router} +} diff --git a/dephy-vending_machine-examples/balance-payment/app/src/app/app.tsx b/dephy-vending_machine-examples/balance-payment/app/src/app/app.tsx new file mode 100644 index 0000000..c161833 --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/app/src/app/app.tsx @@ -0,0 +1,18 @@ +import { QueryClient, QueryClientProvider } from '@tanstack/react-query' +import { ClusterProvider } from '../components/cluster/cluster-data-access' +import { SolanaProvider } from '../components/solana/solana-provider' +import { AppRoutes } from './app-routes' + +const client = new QueryClient() + +export function App() { + return ( + + + + + + + + ) +} diff --git a/dephy-vending_machine-examples/balance-payment/app/src/app/favicon.ico b/dephy-vending_machine-examples/balance-payment/app/src/app/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..3bc594ba204b02354f41e633d1703529b3e863b1 GIT binary patch literal 32038 zcmeHPPbhU;6hE)N2_~plCjKO^K2jK%n7D~Iz>Ewiy`;R)K#?*LFNq|j48%Z^0h6bc zAxdGugbYmZMJWT30kgN?`5oUnZRhUu=U(UE&02NrefC~^uRr^@*52pb>uTC>+BYpX zSJTT9?eA}z_NS(4B_;3o8+!Y{dRuk%ulqkVt>br1OC;X!zc*;we|4JnT_2;f>NC8z z>xHIIt0JK{@+JA8w6s*Tx3`-y_>%#CME=^si{d|EC_9Gf_WXJ>mFKR7rj*4Nj?@$s=C7k@4;F2wTkvL_wDcXM-N$fXIO1KPH>wmj(o zJ7oD7E8FH)@9F6=M5DwyfMA!~IO?~qALhY2P(PO+;$3$~`h+}FqF)L9LcTHxi6@!Z z|5A?8-NXK1A20@Dh=CtJeu%TPGci0ooU}g0#l>QLd|cGk)g|@$5!1Q3xyF7+f4aN7 zO*vInRpROC$>@4}dlTUGL#A~O*iHm_Bu8$)ySo!PIXQvIr#+u^n4h0Fe2#nA4N|R* z)sD~HudJ*Xa#Vi~4h{mb8|&N9&>*U-tBsOuwdw#&0EgfQ?`Q0!vB11ccCx`keN=92 zYA2D0w0t*utE<~?M~ynff= z3tC$UMcf1PGC@DT<5kFa{#SfbRO}2=6KMSEkxu`enYSDAR9}DYCq(tHQF` z2aEy60AqkLz!+c*Fa{#RKq8S4Wo2a<=l{aOLUDR}O0Oxz^z^i?4fsrXY-~*I?d=(5 z9L}H6*GgSoT}d`r?ZlXok&z_6ux*;1owcej9v>eC^p$lvJUle{o}ZtM`r_i^2OgO} zta?pNjj5MhSzB8(b%UQ()YjH!@`R)qb-d6ucf6$rIs&kuqWts!2SuM9PW$aza~Mv2dzKyeGt0C1gEoypLPMK zhyh%EeSOA-{DZvWMu->i(l{#N7e94OXD+*3Z?!27x?1g1orA1;(>?Y&?0MEXqPoX9 zK}FaPDBi98us14wt#ak_Kk11Wr!y#WzLn&D>wIC};~b+R#3kur$D?{qpfO>Us&kKg zb|yVk@gdttd|{V(CdB?vY%6f90 zKO18VFa{U{i~+^~V}LOb7zT9LGDYP9d`~N(U;pTr`8_Q(B$MmeULV3d>;uLCV}LQh z7+?%A1{ed30mcAhfHA-rU<@z@7z2!fBn&h*Hj1UCC9$xuAex(-lltA>D-{(Lr98%M z&anFX`}@t$^r-?rc#)5>CnqQ3{{CLdMX(V~wqT1}^LfJ_Dw# zW8!>2Iy!1+j?v!H(P7#Hyud~~Qho0!&bC80td|o8klScYcXoE{OgGwt`i-cdeTX%7 zqM4Z);e>mP^}1&SZA-fIJLNRkXSYwF5BMRBq$@w_ame++dOFnE*=gp8sO|WSe4PDK zrA*6t$WcQ>LjrjpCC+eIKjZ+|k26dvgz-2(V=PLlV@_OlXNb?NQ@Uf__PSK;_R5R> zvbMH1^7z2HEGmjajHDCWe)$W}Na2~kCWYA{Db`}RXRF4iafTx*yhIL_H5_mmrOtV z!#7UPc8FuAXGHi0`-_{8ClZ({|Fw>0Jr-PU6dy($0Rg+u4B6N>mhwbFQ7v zcI~R?0^rywm!S`N!Af|(w38F(cEmW|@gcv-?|YqeMlJw9-Wef(0uxR?bDArY`(X1| vv^$g6jCJS#lVA)m1{ed30mcAhfHA-rU<@z@7z2y}#z1T_pf3&6SM|XEay{>8 literal 0 HcmV?d00001 diff --git a/dephy-vending_machine-examples/balance-payment/app/src/assets/react.svg b/dephy-vending_machine-examples/balance-payment/app/src/assets/react.svg new file mode 100644 index 0000000..8e0e0f1 --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/app/src/assets/react.svg @@ -0,0 +1 @@ + diff --git a/dephy-vending_machine-examples/balance-payment/app/src/components/account/account-data-access.tsx b/dephy-vending_machine-examples/balance-payment/app/src/components/account/account-data-access.tsx new file mode 100644 index 0000000..d1a7678 --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/app/src/components/account/account-data-access.tsx @@ -0,0 +1,174 @@ +import { TOKEN_2022_PROGRAM_ID, TOKEN_PROGRAM_ID } from '@solana/spl-token' +import { useConnection, useWallet } from '@solana/wallet-adapter-react' +import { + Connection, + LAMPORTS_PER_SOL, + PublicKey, + SystemProgram, + TransactionMessage, + TransactionSignature, + VersionedTransaction, +} from '@solana/web3.js' +import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query' +import toast from 'react-hot-toast' +import { useTransactionToast } from '../ui/ui-layout' + +export function useGetBalance({ address }: { address: PublicKey }) { + const { connection } = useConnection() + + return useQuery({ + queryKey: ['get-balance', { endpoint: connection.rpcEndpoint, address }], + queryFn: () => connection.getBalance(address), + }) +} + +export function useGetSignatures({ address }: { address: PublicKey }) { + const { connection } = useConnection() + + return useQuery({ + queryKey: ['get-signatures', { endpoint: connection.rpcEndpoint, address }], + queryFn: () => connection.getSignaturesForAddress(address), + }) +} + +export function useGetTokenAccounts({ address }: { address: PublicKey }) { + const { connection } = useConnection() + + return useQuery({ + queryKey: ['get-token-accounts', { endpoint: connection.rpcEndpoint, address }], + queryFn: async () => { + const [tokenAccounts, token2022Accounts] = await Promise.all([ + connection.getParsedTokenAccountsByOwner(address, { + programId: TOKEN_PROGRAM_ID, + }), + connection.getParsedTokenAccountsByOwner(address, { + programId: TOKEN_2022_PROGRAM_ID, + }), + ]) + return [...tokenAccounts.value, ...token2022Accounts.value] + }, + }) +} + +export function useTransferSol({ address }: { address: PublicKey }) { + const { connection } = useConnection() + const transactionToast = useTransactionToast() + const wallet = useWallet() + const client = useQueryClient() + + return useMutation({ + mutationKey: ['transfer-sol', { endpoint: connection.rpcEndpoint, address }], + mutationFn: async (input: { destination: PublicKey; amount: number }) => { + let signature: TransactionSignature = '' + try { + const { transaction, latestBlockhash } = await createTransaction({ + publicKey: address, + destination: input.destination, + amount: input.amount, + connection, + }) + + // Send transaction and await for signature + signature = await wallet.sendTransaction(transaction, connection) + + // Send transaction and await for signature + await connection.confirmTransaction({ signature, ...latestBlockhash }, 'confirmed') + + console.log(signature) + return signature + } catch (error: unknown) { + console.log('error', `Transaction failed! ${error}`, signature) + + return + } + }, + onSuccess: (signature) => { + if (signature) { + transactionToast(signature) + } + return Promise.all([ + client.invalidateQueries({ + queryKey: ['get-balance', { endpoint: connection.rpcEndpoint, address }], + }), + client.invalidateQueries({ + queryKey: ['get-signatures', { endpoint: connection.rpcEndpoint, address }], + }), + ]) + }, + onError: (error) => { + toast.error(`Transaction failed! ${error}`) + }, + }) +} + +export function useRequestAirdrop({ address }: { address: PublicKey }) { + const { connection } = useConnection() + const transactionToast = useTransactionToast() + const client = useQueryClient() + + return useMutation({ + mutationKey: ['airdrop', { endpoint: connection.rpcEndpoint, address }], + mutationFn: async (amount: number = 1) => { + const [latestBlockhash, signature] = await Promise.all([ + connection.getLatestBlockhash(), + connection.requestAirdrop(address, amount * LAMPORTS_PER_SOL), + ]) + + await connection.confirmTransaction({ signature, ...latestBlockhash }, 'confirmed') + return signature + }, + onSuccess: (signature) => { + transactionToast(signature) + return Promise.all([ + client.invalidateQueries({ + queryKey: ['get-balance', { endpoint: connection.rpcEndpoint, address }], + }), + client.invalidateQueries({ + queryKey: ['get-signatures', { endpoint: connection.rpcEndpoint, address }], + }), + ]) + }, + }) +} + +async function createTransaction({ + publicKey, + destination, + amount, + connection, +}: { + publicKey: PublicKey + destination: PublicKey + amount: number + connection: Connection +}): Promise<{ + transaction: VersionedTransaction + latestBlockhash: { blockhash: string; lastValidBlockHeight: number } +}> { + // Get the latest blockhash to use in our transaction + const latestBlockhash = await connection.getLatestBlockhash() + + // Create instructions to send, in this case a simple transfer + const instructions = [ + SystemProgram.transfer({ + fromPubkey: publicKey, + toPubkey: destination, + lamports: amount * LAMPORTS_PER_SOL, + }), + ] + + // Create a new TransactionMessage with version and compile it to legacy + const messageLegacy = new TransactionMessage({ + payerKey: publicKey, + recentBlockhash: latestBlockhash.blockhash, + instructions, + }).compileToLegacyMessage() + + // Create a new VersionedTransaction which supports legacy and v0 + const transaction = new VersionedTransaction(messageLegacy) + + return { + transaction, + latestBlockhash, + } +} diff --git a/dephy-vending_machine-examples/balance-payment/app/src/components/account/account-detail-feature.tsx b/dephy-vending_machine-examples/balance-payment/app/src/components/account/account-detail-feature.tsx new file mode 100644 index 0000000..0d4869e --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/app/src/components/account/account-detail-feature.tsx @@ -0,0 +1,44 @@ +import { PublicKey } from '@solana/web3.js' +import { useMemo } from 'react' +import { useParams } from 'react-router' +import { ExplorerLink } from '../cluster/cluster-ui' +import { AppHero, ellipsify } from '../ui/ui-layout' +import { AccountBalance, AccountButtons, AccountTokens, AccountTransactions } from './account-ui' + +export default function AccountDetailFeature() { + const params = useParams() as { address?: string } + const address = useMemo(() => { + if (!params.address) { + return + } + try { + return new PublicKey(params.address) + } catch (e) { + console.log(`Invalid public key`, e) + } + }, [params]) + if (!address) { + return
Error loading account
+ } + + return ( +
+ } + subtitle={ +
+ +
+ } + > +
+ +
+
+
+ + +
+
+ ) +} diff --git a/dephy-vending_machine-examples/balance-payment/app/src/components/account/account-list-feature.tsx b/dephy-vending_machine-examples/balance-payment/app/src/components/account/account-list-feature.tsx new file mode 100644 index 0000000..04d351a --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/app/src/components/account/account-list-feature.tsx @@ -0,0 +1,19 @@ +import { useWallet } from '@solana/wallet-adapter-react' +import { Navigate } from 'react-router' +import { WalletButton } from '../solana/solana-provider' + +export default function AccountListFeature() { + const { publicKey } = useWallet() + + if (publicKey) { + return + } + + return ( +
+
+ +
+
+ ) +} diff --git a/dephy-vending_machine-examples/balance-payment/app/src/components/account/account-ui.tsx b/dephy-vending_machine-examples/balance-payment/app/src/components/account/account-ui.tsx new file mode 100644 index 0000000..0c1bf09 --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/app/src/components/account/account-ui.tsx @@ -0,0 +1,347 @@ +import { useWallet } from '@solana/wallet-adapter-react' +import { LAMPORTS_PER_SOL, PublicKey } from '@solana/web3.js' +import { IconRefresh } from '@tabler/icons-react' +import { useQueryClient } from '@tanstack/react-query' +import { useMemo, useState } from 'react' +import { useCluster } from '../cluster/cluster-data-access' +import { ExplorerLink } from '../cluster/cluster-ui' +import { AppModal, ellipsify } from '../ui/ui-layout' +import { + useGetBalance, + useGetSignatures, + useGetTokenAccounts, + useRequestAirdrop, + useTransferSol, +} from './account-data-access' + +export function AccountBalance({ address }: { address: PublicKey }) { + const query = useGetBalance({ address }) + + return ( +
+

query.refetch()}> + {query.data ? : '...'} SOL +

+
+ ) +} +export function AccountChecker() { + const { publicKey } = useWallet() + if (!publicKey) { + return null + } + return +} +export function AccountBalanceCheck({ address }: { address: PublicKey }) { + const { cluster } = useCluster() + const mutation = useRequestAirdrop({ address }) + const query = useGetBalance({ address }) + + if (query.isLoading) { + return null + } + if (query.isError || !query.data) { + return ( +
+ + You are connected to {cluster.name} but your account is not found on this cluster. + + +
+ ) + } + return null +} + +export function AccountButtons({ address }: { address: PublicKey }) { + const wallet = useWallet() + const { cluster } = useCluster() + const [showAirdropModal, setShowAirdropModal] = useState(false) + const [showReceiveModal, setShowReceiveModal] = useState(false) + const [showSendModal, setShowSendModal] = useState(false) + + return ( +
+ setShowAirdropModal(false)} address={address} show={showAirdropModal} /> + setShowReceiveModal(false)} /> + setShowSendModal(false)} /> +
+ + + +
+
+ ) +} + +export function AccountTokens({ address }: { address: PublicKey }) { + const [showAll, setShowAll] = useState(false) + const query = useGetTokenAccounts({ address }) + const client = useQueryClient() + const items = useMemo(() => { + if (showAll) return query.data + return query.data?.slice(0, 5) + }, [query.data, showAll]) + + return ( +
+
+
+

Token Accounts

+
+ {query.isLoading ? ( + + ) : ( + + )} +
+
+
+ {query.isError &&
Error: {query.error?.message.toString()}
} + {query.isSuccess && ( +
+ {query.data.length === 0 ? ( +
No token accounts found.
+ ) : ( + + + + + + + + + + {items?.map(({ account, pubkey }) => ( + + + + + + ))} + + {(query.data?.length ?? 0) > 5 && ( + + + + )} + +
Public KeyMintBalance
+
+ + + +
+
+
+ + + +
+
+ {account.data.parsed.info.tokenAmount.uiAmount} +
+ +
+ )} +
+ )} +
+ ) +} + +export function AccountTransactions({ address }: { address: PublicKey }) { + const query = useGetSignatures({ address }) + const [showAll, setShowAll] = useState(false) + + const items = useMemo(() => { + if (showAll) return query.data + return query.data?.slice(0, 5) + }, [query.data, showAll]) + + return ( +
+
+

Transaction History

+
+ {query.isLoading ? ( + + ) : ( + + )} +
+
+ {query.isError &&
Error: {query.error?.message.toString()}
} + {query.isSuccess && ( +
+ {query.data.length === 0 ? ( +
No transactions found.
+ ) : ( + + + + + + + + + + + {items?.map((item) => ( + + + + + + + ))} + {(query.data?.length ?? 0) > 5 && ( + + + + )} + +
SignatureSlotBlock TimeStatus
+ + + + {new Date((item.blockTime ?? 0) * 1000).toISOString()} + {item.err ? ( +
+ Failed +
+ ) : ( +
Success
+ )} +
+ +
+ )} +
+ )} +
+ ) +} + +function BalanceSol({ balance }: { balance: number }) { + return {Math.round((balance / LAMPORTS_PER_SOL) * 100000) / 100000} +} + +function ModalReceive({ hide, show, address }: { hide: () => void; show: boolean; address: PublicKey }) { + return ( + +

Receive assets by sending them to your public key:

+ {address.toString()} +
+ ) +} + +function ModalAirdrop({ hide, show, address }: { hide: () => void; show: boolean; address: PublicKey }) { + const mutation = useRequestAirdrop({ address }) + const [amount, setAmount] = useState('2') + + return ( + mutation.mutateAsync(parseFloat(amount)).then(() => hide())} + > + setAmount(e.target.value)} + /> + + ) +} + +function ModalSend({ hide, show, address }: { hide: () => void; show: boolean; address: PublicKey }) { + const wallet = useWallet() + const mutation = useTransferSol({ address }) + const [destination, setDestination] = useState('') + const [amount, setAmount] = useState('1') + + if (!address || !wallet.sendTransaction) { + return
Wallet not connected
+ } + + return ( + { + mutation + .mutateAsync({ + destination: new PublicKey(destination), + amount: parseFloat(amount), + }) + .then(() => hide()) + }} + > + setDestination(e.target.value)} + /> + setAmount(e.target.value)} + /> + + ) +} diff --git a/dephy-vending_machine-examples/balance-payment/app/src/components/balance-payment/balance-payment-data-access.tsx b/dephy-vending_machine-examples/balance-payment/app/src/components/balance-payment/balance-payment-data-access.tsx new file mode 100644 index 0000000..8013e85 --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/app/src/components/balance-payment/balance-payment-data-access.tsx @@ -0,0 +1,72 @@ +import { getBalancePaymentProgram, getBalancePaymentProgramId } from '../../anchor' +import { Cluster } from '@solana/web3.js' +import { v4 as uuidv4 } from "uuid"; +import { useMemo } from 'react' +import { useCluster } from '../cluster/cluster-data-access' +import { useAnchorProvider } from '../solana/solana-provider' +import { BN, web3 } from '@coral-xyz/anchor' + +export function useBalancePaymentProgram() { + const { cluster } = useCluster() + const provider = useAnchorProvider() + const programId = useMemo(() => getBalancePaymentProgramId(cluster.network as Cluster), [cluster]) + const program = useMemo(() => getBalancePaymentProgram(provider, programId), [provider, programId]) + + const getGlobalPubkey = () => { + const [globalAccountPubkey, _] = web3.PublicKey.findProgramAddressSync( + [Buffer.from("GLOBAL")], + programId + ); + return globalAccountPubkey; + } + + const getUserAccountPubkey = (user: web3.PublicKey) => { + const [userAccountPubkey, _] = web3.PublicKey.findProgramAddressSync( + [Buffer.from("USER"), user.toBuffer()], + programId + ); + return userAccountPubkey; + }; + + const getUserVaultPubkey = (user: web3.PublicKey) => { + const [vaultPubkey, _] = web3.PublicKey.findProgramAddressSync( + [Buffer.from("VAULT"), user.toBuffer()], + programId + ); + return vaultPubkey; + }; + + const getLockAccountPubkey = (user: web3.PublicKey, nonce: BN) => { + const [lockAccountPubkey, _] = web3.PublicKey.findProgramAddressSync( + [ + Buffer.from("LOCK"), + user.toBuffer(), + nonce.toArrayLike(Buffer, "le", 8), + ], + program.programId + ); + return lockAccountPubkey; + }; + + const generate64ByteUUIDPayload = () => { + const uuid = uuidv4().replace(/-/g, ""); // 去掉连字符 + const uuidBuffer = Buffer.from(uuid, "hex"); + + const extendedBuffer = Buffer.concat([uuidBuffer, Buffer.alloc(48, 0)]); + + return { + uuid, + uuidBytes: extendedBuffer + }; + }; + + return { + program, + programId, + getGlobalPubkey, + getUserAccountPubkey, + getUserVaultPubkey, + getLockAccountPubkey, + generate64ByteUUIDPayload + } +} diff --git a/dephy-vending_machine-examples/balance-payment/app/src/components/balance-payment/balance-payment-feature.tsx b/dephy-vending_machine-examples/balance-payment/app/src/components/balance-payment/balance-payment-feature.tsx new file mode 100644 index 0000000..c68f338 --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/app/src/components/balance-payment/balance-payment-feature.tsx @@ -0,0 +1,721 @@ +import { useWallet } from '@solana/wallet-adapter-react' +import { WalletButton } from '../solana/solana-provider' +import { useBalancePaymentProgram } from './balance-payment-data-access' +import { useEffect, useState, useRef } from 'react' +import { BN } from '@coral-xyz/anchor' +import keccak from 'keccak' +import { useTransactionToast } from '../ui/ui-layout' +import toast from 'react-hot-toast' +import { finalizeEvent, generateSecretKey } from 'nostr-tools/pure' +import { Relay } from 'nostr-tools/relay' +import bs58 from 'bs58' + +const SIGN_MESSAGE_PREFIX = 'DePHY vending machine/Example:\n' +const RELAY_ENDPOINT = import.meta.env.VITE_RELAY_ENDPOINT || 'ws://127.0.0.1:8000' + +// define charge status +type ChargeStatus = 'idle' | 'requested' | 'working' | 'available' | 'error' + +export default function BalancePaymentFeature() { + const transactionToast = useTransactionToast() + const { publicKey, wallet, signMessage } = useWallet() + const { program, getGlobalPubkey, getUserAccountPubkey, generate64ByteUUIDPayload } = useBalancePaymentProgram() + + const [selectedTab, setSelectedTab] = useState<'decharge' | 'gacha'>('decharge') + const [recoverInfo, setRecoverInfo] = useState() + const [serialNumberStr, setSerialNumberStr] = useState(null) + const [serialNumberBytes, setSerialNumberBytes] = useState(null) + const [globalAccount, setGlobalAccount] = useState(null) + const [userAccount, setUserAccount] = useState(null) + const [vaultBalance, setVaultBalance] = useState(null) + const [depositAmount, setDepositAmount] = useState('') + const [withdrawAmount, setWithdrawAmount] = useState('') + const [machinePubkey, setMachinePubkey] = useState( + 'd041ea9854f2117b82452457c4e6d6593a96524027cd4032d2f40046deb78d93', + ) + const [relay, setRelay] = useState() + const [sk, setSk] = useState(null) + const [chargeStatus, setChargeStatus] = useState('idle') + const [events, setEvents] = useState([]) + const [expandedEventIndex, setExpandedEventIndex] = useState(null) + const [isChargeDisabled, setIsChargeDisabled] = useState(false) + const isTabDisabled = chargeStatus !== 'idle' && chargeStatus !== 'available' + const [initialRequestId, setInitialRequestId] = useState(null) + const [initialPayload, setInitialPayload] = useState(null) + const [stopFlag, setStopFlag] = useState(false) + const [isStopPending, setIsStopPending] = useState(false) + + const subscriptionRef = useRef(null) + + useEffect(() => { + const { uuid, uuidBytes } = generate64ByteUUIDPayload() + setSerialNumberStr(uuid) + setSerialNumberBytes(uuidBytes) + }, [selectedTab]) + + useEffect(() => { + if (!globalAccount) { + fetchGlobalAccount() + } + }, [program]) + + useEffect(() => { + if (!userAccount) { + fetchUserAccount() + } + }, [program, publicKey]) + + useEffect(() => { + if (publicKey) { + const intervalId = setInterval(fetchUserAccount, 3000) + + return () => clearInterval(intervalId) + } + }, [publicKey]) + + useEffect(() => { + ;(async () => { + const sk = generateSecretKey() + setSk(sk) + + try { + const relay = await Relay.connect(RELAY_ENDPOINT) + setRelay(relay) + toast.success(`connected to ${relay.url}`) + } catch (error) { + toast.error(`fail to connect relay, ${error}`) + } + })() + }, []) + + const solToLamports = (sol: string): BN => { + const solNumber = parseFloat(sol) + if (isNaN(solNumber) || solNumber < 0) { + throw new Error('Invalid SOL amount') + } + return new BN(solNumber * 10 ** 9) + } + + const handleRegister = async () => { + if (!publicKey || !program) { + console.error('Wallet not connected or program not loaded') + return + } + + try { + const transactionSignature = await program.methods + .register() + .accountsPartial({ + user: publicKey, + }) + .rpc() + + console.log('Register transaction signature:', transactionSignature) + transactionToast(transactionSignature) + + const userAccountPubkey = getUserAccountPubkey(publicKey) + const user = await program.account.userAccount.fetch(userAccountPubkey) + setUserAccount(user) + const userVaultBalance = await program.provider.connection.getBalance(user.vault) + setVaultBalance(userVaultBalance) + } catch (error) { + toast.error(`Error registering user account: ${error}`) + } + } + + const handleDeposit = async () => { + if (!publicKey || !program || !depositAmount) { + console.error('Wallet not connected or program not loaded or amount not set') + return + } + + try { + const amount = solToLamports(depositAmount) + const transactionSignature = await program.methods + .deposit(amount) + .accountsPartial({ + user: publicKey, + }) + .rpc() + + console.log('Deposit transaction signature:', transactionSignature) + transactionToast(transactionSignature) + + const userAccountPubkey = getUserAccountPubkey(publicKey) + const user = await program.account.userAccount.fetch(userAccountPubkey) + const userVaultBalance = await program.provider.connection.getBalance(user.vault) + setVaultBalance(userVaultBalance) + } catch (error) { + toast.error(`Error depositing: ${error}`) + } + } + + const handleWithdraw = async () => { + if (!publicKey || !program || !withdrawAmount) { + console.error('Wallet not connected or program not loaded or amount not set') + return + } + + try { + const amount = solToLamports(withdrawAmount) + const transactionSignature = await program.methods + .withdraw(amount) + .accountsPartial({ + user: publicKey, + }) + .rpc() + + console.log('Withdraw transaction signature:', transactionSignature) + transactionToast(transactionSignature) + + const userAccountPubkey = getUserAccountPubkey(publicKey) + const user = await program.account.userAccount.fetch(userAccountPubkey) + const userVaultBalance = await program.provider.connection.getBalance(user.vault) + setVaultBalance(userVaultBalance) + } catch (error) { + toast.error(`Error withdrawing: ${error}`) + } + } + + const handleSelectTab = (tab: 'decharge' | 'gacha') => { + if (isTabDisabled) { + return + } + setSelectedTab(tab) + handleReset() + } + + const fetchGlobalAccount = async () => { + if (!program) return + + const globalAccountPubkey = getGlobalPubkey() + const global = await program.account.globalAccount.fetch(globalAccountPubkey) + setGlobalAccount(global) + } + + const fetchUserAccount = async () => { + if (!publicKey || !program) return + + const userAccountPubkey = getUserAccountPubkey(publicKey) + console.log('userAccountPubkey:', userAccountPubkey.toString()) + const user = await program.account.userAccount.fetch(userAccountPubkey) + const userVaultBalance = await program.provider.connection.getBalance(user.vault) + setVaultBalance(userVaultBalance) + setUserAccount(user) + } + + const handleCharge = async () => { + if (!wallet || !publicKey || !signMessage || !serialNumberBytes) { + console.error('Wallet not connected or serial number not generated') + return + } + + setIsChargeDisabled(true) + + const userAccountPubkey = getUserAccountPubkey(publicKey) + const user = await program.account.userAccount.fetch(userAccountPubkey) + + const nonce = user.nonce + const payload = serialNumberBytes + const deadline = new BN(Date.now() / 1000 + 60 * 30) // 30 minutes later + + const message = Buffer.concat([payload, nonce.toArrayLike(Buffer, 'le', 8), deadline.toArrayLike(Buffer, 'le', 8)]) + const messageHash = keccak('keccak256').update(message).digest() + const hashedMessageBase58 = bs58.encode(messageHash) + const digest = new TextEncoder().encode(`${SIGN_MESSAGE_PREFIX}${hashedMessageBase58}`) + + let recoverInfo + try { + const signature = await signMessage(digest) + recoverInfo = { + signature: Array.from(signature), + payload: Array.from(payload), + deadline: deadline.toNumber(), + } + setRecoverInfo(recoverInfo) + } catch (error) { + toast.error(`Error signing message: ${error}`) + setIsChargeDisabled(false) + return + } + + try { + await publishToRelay(nonce.toNumber(), recoverInfo, publicKey.toString()) + } catch (error) { + toast.error(`Error publishing to relay: ${error}`) + setIsChargeDisabled(false) + return + } + + try { + await listenFromRelay() + } catch (error) { + toast.error(`Error listening from relay: ${error}`) + setIsChargeDisabled(false) + } + } + + const handleStop = async () => { + if (!sk || !relay || !machinePubkey || !initialRequestId || !initialPayload) { + toast.error('Not initialized') + return + } + + setIsStopPending(true) + try { + const sTag = selectedTab === 'decharge' ? 'dephy-decharge-controller' : 'dephy-gacha-controller' + const contentData = { + Request: { + to_status: 'Available', + reason: 'UserRequest', + initial_request: initialRequestId, + payload: initialPayload, + }, + } + + const content = JSON.stringify(contentData) + const eventTemplate = { + kind: 1573, + created_at: Math.floor(Date.now() / 1000), + tags: [ + ['s', sTag], + ['p', machinePubkey], + ], + content, + } + const signedEvent = finalizeEvent(eventTemplate, sk) + await relay.publish(signedEvent) + toast.success(`Stop request id [${initialRequestId}]`) + setStopFlag(true) + } catch (error) { + toast.error(`Failed to send stop request: ${error}`) + setIsStopPending(false) + } + } + + const publishToRelay = async (nonce: number, recoverInfo: any, user: string) => { + if (!sk) { + toast.error('sk not initialized') + return + } + if (!machinePubkey) { + toast.error('machinePubkey not initialized') + return + } + if (!relay) { + toast.error('relay not initialized') + return + } + const sTag = selectedTab === 'decharge' ? 'dephy-decharge-controller' : 'dephy-gacha-controller' + + const payload = JSON.stringify({ + recover_info: JSON.stringify(recoverInfo), + nonce, + user, + }) + + setInitialPayload(payload) + + const contentData = { + Request: { + to_status: 'Working', + reason: 'UserRequest', + initial_request: '0000000000000000000000000000000000000000000000000000000000000000', + payload, + }, + } + + const content = JSON.stringify(contentData) + + let eventTemplate = { + kind: 1573, + created_at: Math.floor(Date.now() / 1000), + tags: [ + ['s', sTag], + ['p', machinePubkey], + ], + content, + } + const signedEvent = finalizeEvent(eventTemplate, sk) + await relay.publish(signedEvent) + } + + const listenFromRelay = async () => { + if (!sk) { + toast.error('sk not initialized') + return + } + if (!machinePubkey) { + toast.error('machinePubkey not initialized') + return + } + if (!relay) { + toast.error('relay not initialized') + return + } + + const sTag = selectedTab === 'decharge' ? 'dephy-decharge-controller' : 'dephy-gacha-controller' + + // clear old subscription + if (subscriptionRef.current) { + subscriptionRef.current.close() + } + + // create new subscription + subscriptionRef.current = relay.subscribe( + [ + { + kinds: [1573], + since: Math.floor(Date.now() / 1000), + '#s': [sTag], + '#p': [machinePubkey], + }, + ], + { + onevent: async (event) => { + console.log('event received:', event) + try { + const content = JSON.parse(event.content) + if (content.Request) { + setChargeStatus('requested') + setInitialRequestId(event.id) + } else if (content.Status) { + if (content.Status.status === 'Working') { + setChargeStatus('working') + } else if (content.Status.status === 'Available') { + setChargeStatus('available') + setIsChargeDisabled(false) + } + } + setEvents((prevEvents) => [...prevEvents, event]) + } catch (error) { + console.error('Error parsing event content:', error) + setChargeStatus('error') + setEvents((prevEvents) => [...prevEvents, { error: 'Failed to parse event content', rawEvent: event }]) + } + }, + oneose() { + console.log('eose received') + }, + onclose(reason) { + console.log('close received:', reason) + }, + }, + ) + } + + // reset status + const handleReset = () => { + // clear old subscription + if (subscriptionRef.current) { + subscriptionRef.current.close() + subscriptionRef.current = null + } + + setRecoverInfo(null) + setEvents([]) + setChargeStatus('idle') + setIsChargeDisabled(false) + setInitialRequestId(null) + setInitialPayload(null) + setStopFlag(false) + setIsStopPending(false) + } + + const ProgressBar = () => { + let progress = 0 + // let statusText = '' + let barColor = 'bg-gray-300' // default gray + + const statusTextMap = { + decharge: { + requested: 'Requested - Waiting for charging station...', + working: 'Working - Charging in progress...', + available: `Available - Charging ${stopFlag ? 'stopped' : 'completed'}!`, + error: 'Error - Charging failed!', + idle: 'Idle - Ready to charge', + }, + gacha: { + requested: 'Requested - Waiting for gacha machine...', + working: 'Working - Gacha in progress...', + available: 'Available - Gacha completed!', + error: 'Error - Gacha failed!', + idle: 'Idle - Ready to play', + }, + } + + const statusText = statusTextMap[selectedTab][chargeStatus] + + switch (chargeStatus) { + case 'requested': + progress = 33 + // statusText = 'Requested - Waiting for charging station...' + barColor = 'bg-blue-500' + break + case 'working': + progress = 66 + // statusText = 'Working - Charging in progress...' + barColor = 'bg-blue-500' + break + case 'available': + progress = 100 + // statusText = 'Available - Charging completed!' + barColor = 'bg-green-500' + break + case 'error': + progress = 100 + // statusText = 'Error - Something went wrong!' + barColor = 'bg-red-500' + break + default: + progress = 0 + // statusText = 'Idle - Ready to charge' + barColor = 'bg-gray-300' + } + + return ( +
+
+
+
+

{statusText}

+
+ ) + } + + const EventJsonViewer = ({ event, index }: { event: any; index: number }) => { + const isExpanded = expandedEventIndex === index + + const toggleExpand = () => { + if (isExpanded) { + setExpandedEventIndex(null) + } else { + setExpandedEventIndex(index) + } + } + + const getPurpose = () => { + const sTag = event.tags.find((t: string[]) => t[0] === 's')?.[1] + const eventType = sTag === 'dephy-decharge-controller' ? 'Decharge' : 'Gacha' + + try { + const content = JSON.parse(event.content) + if (content.Request) return `${eventType} Request` + if (content.Status) return `${eventType} Status: ${content.Status.status}` + } catch { + return 'Invalid Event' + } + return 'Unknown Event' + } + + const formatTime = (timestamp: number) => { + return new Date(timestamp * 1000).toLocaleString() + } + + return ( +
+
+ + {isExpanded ? '▲' : '▼'} + Event {index + 1} - {getPurpose()} + +
+ {formatTime(event.created_at)} +
+
+ {isExpanded && ( +
{JSON.stringify(event, null, 2)}
+ )} +
+ ) + } + + return publicKey ? ( +
+ {/* Tab */} +
+ + +
+ +
+ {/* userAccount */} +
+

User Account

+ {userAccount ? ( +
+

+ Nonce: {userAccount.nonce.toString()} +

+

+ Locked Amount:{' '} + {userAccount.lockedAmount.toNumber() / 10 ** 9} SOL +

+

+ Vault: {userAccount.vault.toString()} +

+

+ Vault Balance:{' '} + {vaultBalance ? `${vaultBalance / 10 ** 9} SOL` : 'Loading...'} +

+
+ ) : ( +
+

No user account data found.

+ +
+ )} +
+ + {/* deposit */} +
+

Deposit

+
+ setDepositAmount(e.target.value)} + className="input input-bordered w-full placeholder:text-sm" + /> + +
+
+ + {/* withdraw */} +
+

Withdraw

+
+ setWithdrawAmount(e.target.value)} + className="input input-bordered w-full placeholder:text-sm" + /> + +
+
+
+ +
+

{selectedTab === 'decharge' ? 'Charge' : 'Gacha'}

+ + + {events.map((event, index) => ( + + ))} + + {/* reset */} + {chargeStatus === 'available' && ( + + )} + + {serialNumberBytes && ( +
+

Charger Serial Number

+

{serialNumberStr}

+
+ )} + +
+

Machine Pubkey

+ setMachinePubkey(e.target.value)} + className="input input-bordered w-full placeholder:text-sm mt-4" + /> +
+ + {/* charge */} + + + {/* stop */} + {selectedTab === 'decharge' && ( + + )} + + {recoverInfo && ( +
+

Recover Info

+
+

+ Signature:{' '} + {recoverInfo.signature.join(', ')} +

+

+ Payload:{' '} + {recoverInfo.payload.join(', ')} +

+

+ Deadline: {recoverInfo.deadline.toString()} +

+
+
+ )} +
+
+ ) : ( +
+
+
+ +
+
+
+ ) +} diff --git a/dephy-vending_machine-examples/balance-payment/app/src/components/cluster/cluster-data-access.tsx b/dephy-vending_machine-examples/balance-payment/app/src/components/cluster/cluster-data-access.tsx new file mode 100644 index 0000000..2da2f4a --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/app/src/components/cluster/cluster-data-access.tsx @@ -0,0 +1,118 @@ +import { clusterApiUrl, Connection } from '@solana/web3.js' + +import { atom, useAtomValue, useSetAtom } from 'jotai' +import { atomWithStorage } from 'jotai/utils' +import { createContext, ReactNode, useContext } from 'react' +import toast from 'react-hot-toast' + +export interface Cluster { + name: string + endpoint: string + network?: ClusterNetwork + active?: boolean +} + +export enum ClusterNetwork { + Mainnet = 'mainnet-beta', + Testnet = 'testnet', + Devnet = 'devnet', + Custom = 'custom', +} + +// By default, we don't configure the mainnet-beta cluster +// The endpoint provided by clusterApiUrl('mainnet-beta') does not allow access from the browser due to CORS restrictions +// To use the mainnet-beta cluster, provide a custom endpoint +export const defaultClusters: Cluster[] = [ + { + name: 'devnet', + endpoint: clusterApiUrl('devnet'), + network: ClusterNetwork.Devnet, + }, + { name: 'local', endpoint: 'http://localhost:8899' }, + { + name: 'testnet', + endpoint: clusterApiUrl('testnet'), + network: ClusterNetwork.Testnet, + }, +] + +const index = import.meta.env.VITE_NETWORK === "devnet" ? 0 : 1; // default is local if `VITE_NETWORK` env not provided + +const clusterAtom = atomWithStorage('solana-cluster', defaultClusters[index]) +const clustersAtom = atomWithStorage('solana-clusters', defaultClusters) + +const activeClustersAtom = atom((get) => { + const clusters = get(clustersAtom) + const cluster = get(clusterAtom) + return clusters.map((item) => ({ + ...item, + active: item.name === cluster.name, + })) +}) + +const activeClusterAtom = atom((get) => { + const clusters = get(activeClustersAtom) + + return clusters.find((item) => item.active) || clusters[0] +}) + +export interface ClusterProviderContext { + cluster: Cluster + clusters: Cluster[] + addCluster: (cluster: Cluster) => void + deleteCluster: (cluster: Cluster) => void + setCluster: (cluster: Cluster) => void + getExplorerUrl(path: string): string +} + +const Context = createContext({} as ClusterProviderContext) + +export function ClusterProvider({ children }: { children: ReactNode }) { + const cluster = useAtomValue(activeClusterAtom) + const clusters = useAtomValue(activeClustersAtom) + const setCluster = useSetAtom(clusterAtom) + const setClusters = useSetAtom(clustersAtom) + + const value: ClusterProviderContext = { + cluster, + clusters: clusters.sort((a, b) => (a.name > b.name ? 1 : -1)), + addCluster: (cluster: Cluster) => { + try { + new Connection(cluster.endpoint) + setClusters([...clusters, cluster]) + } catch (err) { + toast.error(`${err}`) + } + }, + deleteCluster: (cluster: Cluster) => { + setClusters(clusters.filter((item) => item.name !== cluster.name)) + }, + setCluster: (cluster: Cluster) => setCluster(cluster), + getExplorerUrl: (path: string) => `https://explorer.solana.com/${path}${getClusterUrlParam(cluster)}`, + } + return {children} +} + +export function useCluster() { + return useContext(Context) +} + +function getClusterUrlParam(cluster: Cluster): string { + let suffix = '' + switch (cluster.network) { + case ClusterNetwork.Devnet: + suffix = 'devnet' + break + case ClusterNetwork.Mainnet: + suffix = '' + break + case ClusterNetwork.Testnet: + suffix = 'testnet' + break + default: + suffix = `custom&customUrl=${encodeURIComponent(cluster.endpoint)}` + break + } + + return suffix.length ? `?cluster=${suffix}` : '' +} diff --git a/dephy-vending_machine-examples/balance-payment/app/src/components/cluster/cluster-feature.tsx b/dephy-vending_machine-examples/balance-payment/app/src/components/cluster/cluster-feature.tsx new file mode 100644 index 0000000..e7608aa --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/app/src/components/cluster/cluster-feature.tsx @@ -0,0 +1,19 @@ +import { useState } from 'react' +import { AppHero } from '../ui/ui-layout' +import { ClusterUiModal, ClusterUiTable } from './cluster-ui' + +export default function ClusterFeature() { + const [showModal, setShowModal] = useState(false) + + return ( +
+ + setShowModal(false)} /> + + + +
+ ) +} diff --git a/dephy-vending_machine-examples/balance-payment/app/src/components/cluster/cluster-ui.tsx b/dephy-vending_machine-examples/balance-payment/app/src/components/cluster/cluster-ui.tsx new file mode 100644 index 0000000..ce62148 --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/app/src/components/cluster/cluster-ui.tsx @@ -0,0 +1,172 @@ +import { useConnection } from '@solana/wallet-adapter-react' +import { Connection } from '@solana/web3.js' +import { IconTrash } from '@tabler/icons-react' +import { useQuery } from '@tanstack/react-query' +import { ReactNode, useState } from 'react' +import { AppModal } from '../ui/ui-layout' +import { ClusterNetwork, useCluster } from './cluster-data-access' + +export function ExplorerLink({ path, label, className }: { path: string; label: string; className?: string }) { + const { getExplorerUrl } = useCluster() + return ( + + {label} + + ) +} + +export function ClusterChecker({ children }: { children: ReactNode }) { + const { cluster } = useCluster() + const { connection } = useConnection() + + const query = useQuery({ + queryKey: ['version', { cluster, endpoint: connection.rpcEndpoint }], + queryFn: () => connection.getVersion(), + retry: 1, + }) + if (query.isLoading) { + return null + } + if (query.isError || !query.data) { + return ( +
+ + Error connecting to cluster {cluster.name} + + +
+ ) + } + return children +} + +export function ClusterUiSelect() { + const { clusters, setCluster, cluster } = useCluster() + return ( +
+ +
    + {clusters.map((item) => ( +
  • + +
  • + ))} +
+
+ ) +} + +export function ClusterUiModal({ hideModal, show }: { hideModal: () => void; show: boolean }) { + const { addCluster } = useCluster() + const [name, setName] = useState('') + const [network, setNetwork] = useState() + const [endpoint, setEndpoint] = useState('') + + return ( + { + try { + new Connection(endpoint) + if (name) { + addCluster({ name, network, endpoint }) + hideModal() + } else { + console.log('Invalid cluster name') + } + } catch { + console.log('Invalid cluster endpoint') + } + }} + submitLabel="Save" + > + setName(e.target.value)} + /> + setEndpoint(e.target.value)} + /> + + + ) +} + +export function ClusterUiTable() { + const { clusters, setCluster, deleteCluster } = useCluster() + return ( +
+ + + + + + + + + {clusters.map((item) => ( + + + + + ))} + +
Name/ Network / EndpointActions
+
+ + {item?.active ? ( + item.name + ) : ( + + )} + +
+ Network: {item.network ?? 'custom'} +
{item.endpoint}
+
+ +
+
+ ) +} diff --git a/dephy-vending_machine-examples/balance-payment/app/src/components/dashboard/dashboard-feature.tsx b/dephy-vending_machine-examples/balance-payment/app/src/components/dashboard/dashboard-feature.tsx new file mode 100644 index 0000000..50b2730 --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/app/src/components/dashboard/dashboard-feature.tsx @@ -0,0 +1,29 @@ +import { AppHero } from '../ui/ui-layout' + +const links: { label: string; href: string }[] = [ + { label: 'Solana Docs', href: 'https://docs.solana.com/' }, + { label: 'Solana Faucet', href: 'https://faucet.solana.com/' }, + { label: 'Solana Cookbook', href: 'https://solanacookbook.com/' }, + { label: 'Solana Stack Overflow', href: 'https://solana.stackexchange.com/' }, + { label: 'Solana Developers GitHub', href: 'https://github.com/solana-developers/' }, +] + +export default function DashboardFeature() { + return ( +
+ +
+
+

Here are some helpful links to get you started.

+ {links.map((link, index) => ( + + ))} +
+
+
+ ) +} diff --git a/dephy-vending_machine-examples/balance-payment/app/src/components/solana/solana-provider.tsx b/dephy-vending_machine-examples/balance-payment/app/src/components/solana/solana-provider.tsx new file mode 100644 index 0000000..b7b316e --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/app/src/components/solana/solana-provider.tsx @@ -0,0 +1,39 @@ +import { AnchorProvider } from '@coral-xyz/anchor' +import { WalletError } from '@solana/wallet-adapter-base' +import { + AnchorWallet, + ConnectionProvider, + useConnection, + useWallet, + WalletProvider, +} from '@solana/wallet-adapter-react' +import { WalletModalProvider, WalletMultiButton } from '@solana/wallet-adapter-react-ui' +import { ReactNode, useCallback, useMemo } from 'react' +import { useCluster } from '../cluster/cluster-data-access' + +import('@solana/wallet-adapter-react-ui/styles.css') + +export const WalletButton = WalletMultiButton + +export function SolanaProvider({ children }: { children: ReactNode }) { + const { cluster } = useCluster() + const endpoint = useMemo(() => cluster.endpoint, [cluster]) + const onError = useCallback((error: WalletError) => { + console.error(error) + }, []) + + return ( + + + {children} + + + ) +} + +export function useAnchorProvider() { + const { connection } = useConnection() + const wallet = useWallet() + + return new AnchorProvider(connection, wallet as AnchorWallet, { commitment: 'confirmed' }) +} diff --git a/dephy-vending_machine-examples/balance-payment/app/src/components/ui/ui-layout.tsx b/dephy-vending_machine-examples/balance-payment/app/src/components/ui/ui-layout.tsx new file mode 100644 index 0000000..55df50f --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/app/src/components/ui/ui-layout.tsx @@ -0,0 +1,156 @@ +import { ReactNode, Suspense, useEffect, useRef } from 'react' +import toast, { Toaster } from 'react-hot-toast' +import { Link, useLocation } from 'react-router-dom' + +import { AccountChecker } from '../account/account-ui' +import { ClusterChecker, ClusterUiSelect, ExplorerLink } from '../cluster/cluster-ui' +import { WalletButton } from '../solana/solana-provider' + +export function UiLayout({ children, links }: { children: ReactNode; links: { label: string; path: string }[] }) { + const pathname = useLocation().pathname + + return ( +
+
+
+ + Payment + +
    + {links.map(({ label, path }) => ( +
  • + + {label} + +
  • + ))} +
+
+
+ + +
+
+ + + +
+ + +
+ } + > + {children} + + +
+ + + ) +} + +export function AppModal({ + children, + title, + hide, + show, + submit, + submitDisabled, + submitLabel, +}: { + children: ReactNode + title: string + hide: () => void + show: boolean + submit?: () => void + submitDisabled?: boolean + submitLabel?: string +}) { + const dialogRef = useRef(null) + + useEffect(() => { + if (!dialogRef.current) return + if (show) { + dialogRef.current.showModal() + } else { + dialogRef.current.close() + } + }, [show, dialogRef]) + + return ( + +
+

{title}

+ {children} +
+
+ {submit ? ( + + ) : null} + +
+
+
+
+ ) +} + +export function AppHero({ + children, + title, + subtitle, +}: { + children?: ReactNode + title: ReactNode + subtitle: ReactNode +}) { + return ( +
+
+
+ {typeof title === 'string' ?

{title}

: title} + {typeof subtitle === 'string' ?

{subtitle}

: subtitle} + {children} +
+
+
+ ) +} + +export function ellipsify(str = '', len = 4) { + if (str.length > 30) { + return str.substring(0, len) + '..' + str.substring(str.length - len, str.length) + } + return str +} + +export function useTransactionToast() { + return (signature: string) => { + toast.success( +
+
Transaction sent
+ +
, + ) + } +} diff --git a/dephy-vending_machine-examples/balance-payment/app/src/index.css b/dephy-vending_machine-examples/balance-payment/app/src/index.css new file mode 100644 index 0000000..3ddb6b1 --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/app/src/index.css @@ -0,0 +1,20 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +html, +body, +#root { + height: 100%; +} + +.wallet-adapter-button-trigger { + background: rgb(100, 26, 230) !important; + border-radius: 8px !important; + padding-left: 16px !important; + padding-right: 16px !important; +} +.wallet-adapter-dropdown-list, +.wallet-adapter-button { + font-family: inherit !important; +} diff --git a/dephy-vending_machine-examples/balance-payment/app/src/main.tsx b/dephy-vending_machine-examples/balance-payment/app/src/main.tsx new file mode 100644 index 0000000..7fc7e3c --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/app/src/main.tsx @@ -0,0 +1,13 @@ +import { StrictMode } from 'react' +import { createRoot } from 'react-dom/client' +import { BrowserRouter } from 'react-router-dom' +import { App } from './app/app.tsx' +import './index.css' + +createRoot(document.getElementById('root')!).render( + + + + + , +) diff --git a/dephy-vending_machine-examples/balance-payment/app/src/vite-env.d.ts b/dephy-vending_machine-examples/balance-payment/app/src/vite-env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/app/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/dephy-vending_machine-examples/balance-payment/app/tailwind.config.ts b/dephy-vending_machine-examples/balance-payment/app/tailwind.config.ts new file mode 100644 index 0000000..1ff77a0 --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/app/tailwind.config.ts @@ -0,0 +1,14 @@ +import type { Config } from 'tailwindcss' + +const config: Config = { + content: [ + './src/pages/**/*.{js,ts,jsx,tsx,mdx}', + './src/components/**/*.{js,ts,jsx,tsx,mdx}', + './src/app/**/*.{js,ts,jsx,tsx,mdx}', + ], + theme: { + extend: {}, + }, + plugins: [require('daisyui')], +} +export default config diff --git a/dephy-vending_machine-examples/balance-payment/app/tsconfig.app.json b/dephy-vending_machine-examples/balance-payment/app/tsconfig.app.json new file mode 100644 index 0000000..2a4ae51 --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/app/tsconfig.app.json @@ -0,0 +1,28 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "paths": { + "@project/anchor": ["./anchor/src"], + "@/*": ["./src/*"] + } + }, + "include": ["src"] +} diff --git a/dephy-vending_machine-examples/balance-payment/app/tsconfig.json b/dephy-vending_machine-examples/balance-payment/app/tsconfig.json new file mode 100644 index 0000000..d32ff68 --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/app/tsconfig.json @@ -0,0 +1,4 @@ +{ + "files": [], + "references": [{ "path": "./tsconfig.app.json" }, { "path": "./tsconfig.node.json" }] +} diff --git a/dephy-vending_machine-examples/balance-payment/app/tsconfig.node.json b/dephy-vending_machine-examples/balance-payment/app/tsconfig.node.json new file mode 100644 index 0000000..8c880e0 --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/app/tsconfig.node.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "target": "ES2022", + "lib": ["ES2023"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["vite.config.ts"] +} diff --git a/dephy-vending_machine-examples/balance-payment/app/vite.config.ts b/dephy-vending_machine-examples/balance-payment/app/vite.config.ts new file mode 100644 index 0000000..84ea80d --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/app/vite.config.ts @@ -0,0 +1,34 @@ +// import { NodeGlobalsPolyfillPlugin } from '@esbuild-plugins/node-globals-polyfill' +import react from '@vitejs/plugin-react' +import { defineConfig } from 'vite' +import { nodePolyfills } from 'vite-plugin-node-polyfills' +import viteTsconfigPaths from 'vite-tsconfig-paths' // https://vitejs.dev/config/ + +// https://vitejs.dev/config/ +export default defineConfig({ + build: { + sourcemap: false, + rollupOptions: { + output: { + manualChunks: { + coral: ['@coral-xyz/anchor'], + jotai: ['jotai'], + react: ['react', 'react-dom'], + reactHotToast: ['react-hot-toast'], + reactRouter: ['react-router', 'react-router-dom'], + solanaWalletAdapters: [ + '@solana/wallet-adapter-base', + '@solana/wallet-adapter-react', + '@solana/wallet-adapter-react-ui', + ], + tabler: ['@tabler/icons-react'], + tanstack: ['@tanstack/react-query'], + }, + }, + }, + }, + define: { + global: 'globalThis', + }, + plugins: [viteTsconfigPaths(), react(), nodePolyfills()], +}) diff --git a/dephy-vending_machine-examples/balance-payment/bot_example_js/.dockerignore b/dephy-vending_machine-examples/balance-payment/bot_example_js/.dockerignore new file mode 100644 index 0000000..98acc26 --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/bot_example_js/.dockerignore @@ -0,0 +1,11 @@ +target/ +tmp/ +log/ +Dockerfile +.dockerignore +.env +.DS_Store +.swp +.vscode +.idea +node_modules diff --git a/dephy-vending_machine-examples/balance-payment/bot_example_js/Dockerfile b/dephy-vending_machine-examples/balance-payment/bot_example_js/Dockerfile new file mode 100644 index 0000000..f03beb5 --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/bot_example_js/Dockerfile @@ -0,0 +1,14 @@ +# syntax=docker/dockerfile:1 +# see all versions at https://hub.docker.com/r/oven/bun/tags +FROM oven/bun:1 + +WORKDIR /opt/balance-payment-bot +COPY . . +RUN bun install --frozen-lockfile + +# ENV SOLANA_NETWORK="devnet" +# ENV SOLANA_RPC="https://api.devnet.solana.com" + +VOLUME ["/opt/solana"] + +ENTRYPOINT ["bun", "run", "index.ts"] diff --git a/dephy-vending_machine-examples/balance-payment/bot_example_js/README.md b/dephy-vending_machine-examples/balance-payment/bot_example_js/README.md new file mode 100644 index 0000000..d17a6e6 --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/bot_example_js/README.md @@ -0,0 +1,36 @@ +Bot example +==== + +## Prepare + +`bun i` + +## Sign Message + +``` +bun run index.ts sign_message --net devnet --rpc "https://api.devnet.solana.com" --keypair "./user.demo.json" --minutes 30 +``` + +## Check Eligible + +``` +bun run index.ts check_eligible --net devnet --rpc "https://api.devnet.solana.com" --user "user Solana address" --amount "0.01" --nonce "nonce from request payload" --recoverInfo "User request content(Base64)" +``` + +## Lock + +``` +bun run index.ts lock --net devnet --rpc "https://api.devnet.solana.com" --keypair "./bot.demo.json" --user "user Solana address" --amount "0.01" --recoverInfo "User request content(Base64)" +``` + +## Settle + +``` +bun run index.ts settle --net devnet --rpc "https://api.devnet.solana.com" --keypair "./bot.demo.json" --user "user Solana address" --nonce "nonce related lock" --amountToTransfer "0.005" +``` + +## Build Docker image + +``` +docker build --platform linux/amd64,linux/arm64 -t balance-payment-bot . +``` diff --git a/dephy-vending_machine-examples/balance-payment/bot_example_js/balance_payment.json b/dephy-vending_machine-examples/balance-payment/bot_example_js/balance_payment.json new file mode 100644 index 0000000..ea09320 --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/bot_example_js/balance_payment.json @@ -0,0 +1,932 @@ +{ + "address": "GguVKxU88NUe3GLtns7Uaa6a8Pjb9USKq3WD1rjZnPS9", + "metadata": { + "name": "balance_payment", + "version": "0.1.0", + "spec": "0.1.0", + "description": "Created with Anchor" + }, + "instructions": [ + { + "name": "deposit", + "discriminator": [ + 242, + 35, + 198, + 137, + 82, + 225, + 242, + 182 + ], + "accounts": [ + { + "name": "user_account", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 85, + 83, + 69, + 82 + ] + }, + { + "kind": "account", + "path": "user" + } + ] + } + }, + { + "name": "user", + "writable": true, + "signer": true + }, + { + "name": "vault", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 86, + 65, + 85, + 76, + 84 + ] + }, + { + "kind": "account", + "path": "user" + } + ] + } + }, + { + "name": "payer", + "writable": true, + "signer": true + }, + { + "name": "system_program", + "address": "11111111111111111111111111111111" + } + ], + "args": [ + { + "name": "amount", + "type": "u64" + } + ] + }, + { + "name": "initialize", + "discriminator": [ + 175, + 175, + 109, + 31, + 13, + 152, + 155, + 237 + ], + "accounts": [ + { + "name": "global_account", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 71, + 76, + 79, + 66, + 65, + 76 + ] + } + ] + } + }, + { + "name": "authority" + }, + { + "name": "treasury" + }, + { + "name": "bot" + }, + { + "name": "payer", + "writable": true, + "signer": true + }, + { + "name": "system_program", + "address": "11111111111111111111111111111111" + } + ], + "args": [] + }, + { + "name": "lock", + "discriminator": [ + 21, + 19, + 208, + 43, + 237, + 62, + 255, + 87 + ], + "accounts": [ + { + "name": "global_account", + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 71, + 76, + 79, + 66, + 65, + 76 + ] + } + ] + } + }, + { + "name": "user_account", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 85, + 83, + 69, + 82 + ] + }, + { + "kind": "account", + "path": "user" + } + ] + } + }, + { + "name": "user", + "writable": true + }, + { + "name": "lock_account", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 76, + 79, + 67, + 75 + ] + }, + { + "kind": "account", + "path": "user" + }, + { + "kind": "account", + "path": "user_account.nonce", + "account": "UserAccount" + } + ] + } + }, + { + "name": "vault", + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 86, + 65, + 85, + 76, + 84 + ] + }, + { + "kind": "account", + "path": "user" + } + ] + } + }, + { + "name": "bot", + "signer": true, + "relations": [ + "global_account" + ] + }, + { + "name": "payer", + "writable": true, + "signer": true + }, + { + "name": "system_program", + "address": "11111111111111111111111111111111" + } + ], + "args": [ + { + "name": "recover_info", + "type": { + "defined": { + "name": "ED25519RecoverInfo" + } + } + }, + { + "name": "amount", + "type": "u64" + } + ] + }, + { + "name": "pay", + "discriminator": [ + 119, + 18, + 216, + 65, + 192, + 117, + 122, + 220 + ], + "accounts": [ + { + "name": "global_account", + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 71, + 76, + 79, + 66, + 65, + 76 + ] + } + ] + } + }, + { + "name": "user_account", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 85, + 83, + 69, + 82 + ] + }, + { + "kind": "account", + "path": "user" + } + ] + } + }, + { + "name": "user", + "writable": true + }, + { + "name": "treasury", + "writable": true + }, + { + "name": "vault", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 86, + 65, + 85, + 76, + 84 + ] + }, + { + "kind": "account", + "path": "user" + } + ] + } + }, + { + "name": "bot", + "signer": true, + "relations": [ + "global_account" + ] + }, + { + "name": "payer", + "writable": true, + "signer": true + }, + { + "name": "system_program", + "address": "11111111111111111111111111111111" + } + ], + "args": [ + { + "name": "recover_info", + "type": { + "defined": { + "name": "ED25519RecoverInfo" + } + } + }, + { + "name": "amount_to_transfer", + "type": "u64" + } + ] + }, + { + "name": "register", + "discriminator": [ + 211, + 124, + 67, + 15, + 211, + 194, + 178, + 240 + ], + "accounts": [ + { + "name": "user_account", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 85, + 83, + 69, + 82 + ] + }, + { + "kind": "account", + "path": "user" + } + ] + } + }, + { + "name": "user", + "signer": true + }, + { + "name": "vault", + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 86, + 65, + 85, + 76, + 84 + ] + }, + { + "kind": "account", + "path": "user" + } + ] + } + }, + { + "name": "payer", + "writable": true, + "signer": true + }, + { + "name": "system_program", + "address": "11111111111111111111111111111111" + } + ], + "args": [] + }, + { + "name": "set_bot", + "discriminator": [ + 136, + 185, + 99, + 236, + 200, + 131, + 204, + 118 + ], + "accounts": [ + { + "name": "global_account", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 71, + 76, + 79, + 66, + 65, + 76 + ] + } + ] + } + }, + { + "name": "authority", + "signer": true, + "relations": [ + "global_account" + ] + }, + { + "name": "bot" + }, + { + "name": "payer", + "writable": true, + "signer": true + } + ], + "args": [] + }, + { + "name": "set_treasury", + "discriminator": [ + 57, + 97, + 196, + 95, + 195, + 206, + 106, + 136 + ], + "accounts": [ + { + "name": "global_account", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 71, + 76, + 79, + 66, + 65, + 76 + ] + } + ] + } + }, + { + "name": "authority", + "signer": true, + "relations": [ + "global_account" + ] + }, + { + "name": "treasury" + }, + { + "name": "payer", + "writable": true, + "signer": true + } + ], + "args": [] + }, + { + "name": "settle", + "discriminator": [ + 175, + 42, + 185, + 87, + 144, + 131, + 102, + 212 + ], + "accounts": [ + { + "name": "global_account", + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 71, + 76, + 79, + 66, + 65, + 76 + ] + } + ] + } + }, + { + "name": "user_account", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 85, + 83, + 69, + 82 + ] + }, + { + "kind": "account", + "path": "user" + } + ] + } + }, + { + "name": "user", + "writable": true + }, + { + "name": "treasury", + "writable": true + }, + { + "name": "lock_account", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 76, + 79, + 67, + 75 + ] + }, + { + "kind": "account", + "path": "user" + }, + { + "kind": "arg", + "path": "nonce" + } + ] + } + }, + { + "name": "vault", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 86, + 65, + 85, + 76, + 84 + ] + }, + { + "kind": "account", + "path": "user" + } + ] + } + }, + { + "name": "bot", + "signer": true, + "relations": [ + "global_account" + ] + }, + { + "name": "payer", + "writable": true, + "signer": true + }, + { + "name": "system_program", + "address": "11111111111111111111111111111111" + } + ], + "args": [ + { + "name": "_nonce", + "type": "u64" + }, + { + "name": "amount_to_transfer", + "type": "u64" + } + ] + }, + { + "name": "withdraw", + "discriminator": [ + 183, + 18, + 70, + 156, + 148, + 109, + 161, + 34 + ], + "accounts": [ + { + "name": "user_account", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 85, + 83, + 69, + 82 + ] + }, + { + "kind": "account", + "path": "user" + } + ] + } + }, + { + "name": "user", + "writable": true, + "signer": true + }, + { + "name": "vault", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 86, + 65, + 85, + 76, + 84 + ] + }, + { + "kind": "account", + "path": "user" + } + ] + } + }, + { + "name": "payer", + "writable": true, + "signer": true + }, + { + "name": "system_program", + "address": "11111111111111111111111111111111" + } + ], + "args": [ + { + "name": "amount", + "type": "u64" + } + ] + } + ], + "accounts": [ + { + "name": "GlobalAccount", + "discriminator": [ + 129, + 105, + 124, + 171, + 189, + 42, + 108, + 69 + ] + }, + { + "name": "LockAccount", + "discriminator": [ + 223, + 64, + 71, + 124, + 255, + 86, + 118, + 192 + ] + }, + { + "name": "UserAccount", + "discriminator": [ + 211, + 33, + 136, + 16, + 186, + 110, + 242, + 127 + ] + } + ], + "errors": [ + { + "code": 6000, + "name": "Unauthorized", + "msg": "Unauthorized access." + }, + { + "code": 6001, + "name": "InsufficientFunds", + "msg": "Insufficient funds." + }, + { + "code": 6002, + "name": "SignatureFormatInvalid", + "msg": "The signature format or recovery ID is incorrect." + }, + { + "code": 6003, + "name": "SignatureRecoveryFailed", + "msg": "Failed to recover public key from signature." + }, + { + "code": 6004, + "name": "SignatureMismatch", + "msg": "The recovered public key does not match the user's public key." + }, + { + "code": 6005, + "name": "SignatureExpired", + "msg": "The signature is expired." + } + ], + "types": [ + { + "name": "ED25519RecoverInfo", + "type": { + "kind": "struct", + "fields": [ + { + "name": "signature", + "type": { + "array": [ + "u8", + 64 + ] + } + }, + { + "name": "payload", + "type": { + "array": [ + "u8", + 64 + ] + } + }, + { + "name": "deadline", + "type": "i64" + } + ] + } + }, + { + "name": "GlobalAccount", + "type": { + "kind": "struct", + "fields": [ + { + "name": "authority", + "type": "pubkey" + }, + { + "name": "bot", + "type": "pubkey" + }, + { + "name": "treasury", + "type": "pubkey" + } + ] + } + }, + { + "name": "LockAccount", + "type": { + "kind": "struct", + "fields": [ + { + "name": "amount", + "type": "u64" + } + ] + } + }, + { + "name": "UserAccount", + "type": { + "kind": "struct", + "fields": [ + { + "name": "nonce", + "type": "u64" + }, + { + "name": "locked_amount", + "type": "u64" + }, + { + "name": "vault", + "type": "pubkey" + } + ] + } + } + ] +} diff --git a/dephy-vending_machine-examples/balance-payment/bot_example_js/balance_payment.ts b/dephy-vending_machine-examples/balance-payment/bot_example_js/balance_payment.ts new file mode 100644 index 0000000..ecda99e --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/bot_example_js/balance_payment.ts @@ -0,0 +1,938 @@ +/** + * Program IDL in camelCase format in order to be used in JS/TS. + * + * Note that this is only a type helper and is not the actual IDL. The original + * IDL can be found at `target/idl/balance_payment.json`. + */ +export type BalancePayment = { + "address": "GguVKxU88NUe3GLtns7Uaa6a8Pjb9USKq3WD1rjZnPS9", + "metadata": { + "name": "balancePayment", + "version": "0.1.0", + "spec": "0.1.0", + "description": "Created with Anchor" + }, + "instructions": [ + { + "name": "deposit", + "discriminator": [ + 242, + 35, + 198, + 137, + 82, + 225, + 242, + 182 + ], + "accounts": [ + { + "name": "userAccount", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 85, + 83, + 69, + 82 + ] + }, + { + "kind": "account", + "path": "user" + } + ] + } + }, + { + "name": "user", + "writable": true, + "signer": true + }, + { + "name": "vault", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 86, + 65, + 85, + 76, + 84 + ] + }, + { + "kind": "account", + "path": "user" + } + ] + } + }, + { + "name": "payer", + "writable": true, + "signer": true + }, + { + "name": "systemProgram", + "address": "11111111111111111111111111111111" + } + ], + "args": [ + { + "name": "amount", + "type": "u64" + } + ] + }, + { + "name": "initialize", + "discriminator": [ + 175, + 175, + 109, + 31, + 13, + 152, + 155, + 237 + ], + "accounts": [ + { + "name": "globalAccount", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 71, + 76, + 79, + 66, + 65, + 76 + ] + } + ] + } + }, + { + "name": "authority" + }, + { + "name": "treasury" + }, + { + "name": "bot" + }, + { + "name": "payer", + "writable": true, + "signer": true + }, + { + "name": "systemProgram", + "address": "11111111111111111111111111111111" + } + ], + "args": [] + }, + { + "name": "lock", + "discriminator": [ + 21, + 19, + 208, + 43, + 237, + 62, + 255, + 87 + ], + "accounts": [ + { + "name": "globalAccount", + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 71, + 76, + 79, + 66, + 65, + 76 + ] + } + ] + } + }, + { + "name": "userAccount", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 85, + 83, + 69, + 82 + ] + }, + { + "kind": "account", + "path": "user" + } + ] + } + }, + { + "name": "user", + "writable": true + }, + { + "name": "lockAccount", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 76, + 79, + 67, + 75 + ] + }, + { + "kind": "account", + "path": "user" + }, + { + "kind": "account", + "path": "user_account.nonce", + "account": "userAccount" + } + ] + } + }, + { + "name": "vault", + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 86, + 65, + 85, + 76, + 84 + ] + }, + { + "kind": "account", + "path": "user" + } + ] + } + }, + { + "name": "bot", + "signer": true, + "relations": [ + "globalAccount" + ] + }, + { + "name": "payer", + "writable": true, + "signer": true + }, + { + "name": "systemProgram", + "address": "11111111111111111111111111111111" + } + ], + "args": [ + { + "name": "recoverInfo", + "type": { + "defined": { + "name": "ed25519RecoverInfo" + } + } + }, + { + "name": "amount", + "type": "u64" + } + ] + }, + { + "name": "pay", + "discriminator": [ + 119, + 18, + 216, + 65, + 192, + 117, + 122, + 220 + ], + "accounts": [ + { + "name": "globalAccount", + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 71, + 76, + 79, + 66, + 65, + 76 + ] + } + ] + } + }, + { + "name": "userAccount", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 85, + 83, + 69, + 82 + ] + }, + { + "kind": "account", + "path": "user" + } + ] + } + }, + { + "name": "user", + "writable": true + }, + { + "name": "treasury", + "writable": true + }, + { + "name": "vault", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 86, + 65, + 85, + 76, + 84 + ] + }, + { + "kind": "account", + "path": "user" + } + ] + } + }, + { + "name": "bot", + "signer": true, + "relations": [ + "globalAccount" + ] + }, + { + "name": "payer", + "writable": true, + "signer": true + }, + { + "name": "systemProgram", + "address": "11111111111111111111111111111111" + } + ], + "args": [ + { + "name": "recoverInfo", + "type": { + "defined": { + "name": "ed25519RecoverInfo" + } + } + }, + { + "name": "amountToTransfer", + "type": "u64" + } + ] + }, + { + "name": "register", + "discriminator": [ + 211, + 124, + 67, + 15, + 211, + 194, + 178, + 240 + ], + "accounts": [ + { + "name": "userAccount", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 85, + 83, + 69, + 82 + ] + }, + { + "kind": "account", + "path": "user" + } + ] + } + }, + { + "name": "user", + "signer": true + }, + { + "name": "vault", + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 86, + 65, + 85, + 76, + 84 + ] + }, + { + "kind": "account", + "path": "user" + } + ] + } + }, + { + "name": "payer", + "writable": true, + "signer": true + }, + { + "name": "systemProgram", + "address": "11111111111111111111111111111111" + } + ], + "args": [] + }, + { + "name": "setBot", + "discriminator": [ + 136, + 185, + 99, + 236, + 200, + 131, + 204, + 118 + ], + "accounts": [ + { + "name": "globalAccount", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 71, + 76, + 79, + 66, + 65, + 76 + ] + } + ] + } + }, + { + "name": "authority", + "signer": true, + "relations": [ + "globalAccount" + ] + }, + { + "name": "bot" + }, + { + "name": "payer", + "writable": true, + "signer": true + } + ], + "args": [] + }, + { + "name": "setTreasury", + "discriminator": [ + 57, + 97, + 196, + 95, + 195, + 206, + 106, + 136 + ], + "accounts": [ + { + "name": "globalAccount", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 71, + 76, + 79, + 66, + 65, + 76 + ] + } + ] + } + }, + { + "name": "authority", + "signer": true, + "relations": [ + "globalAccount" + ] + }, + { + "name": "treasury" + }, + { + "name": "payer", + "writable": true, + "signer": true + } + ], + "args": [] + }, + { + "name": "settle", + "discriminator": [ + 175, + 42, + 185, + 87, + 144, + 131, + 102, + 212 + ], + "accounts": [ + { + "name": "globalAccount", + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 71, + 76, + 79, + 66, + 65, + 76 + ] + } + ] + } + }, + { + "name": "userAccount", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 85, + 83, + 69, + 82 + ] + }, + { + "kind": "account", + "path": "user" + } + ] + } + }, + { + "name": "user", + "writable": true + }, + { + "name": "treasury", + "writable": true + }, + { + "name": "lockAccount", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 76, + 79, + 67, + 75 + ] + }, + { + "kind": "account", + "path": "user" + }, + { + "kind": "arg", + "path": "nonce" + } + ] + } + }, + { + "name": "vault", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 86, + 65, + 85, + 76, + 84 + ] + }, + { + "kind": "account", + "path": "user" + } + ] + } + }, + { + "name": "bot", + "signer": true, + "relations": [ + "globalAccount" + ] + }, + { + "name": "payer", + "writable": true, + "signer": true + }, + { + "name": "systemProgram", + "address": "11111111111111111111111111111111" + } + ], + "args": [ + { + "name": "nonce", + "type": "u64" + }, + { + "name": "amountToTransfer", + "type": "u64" + } + ] + }, + { + "name": "withdraw", + "discriminator": [ + 183, + 18, + 70, + 156, + 148, + 109, + 161, + 34 + ], + "accounts": [ + { + "name": "userAccount", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 85, + 83, + 69, + 82 + ] + }, + { + "kind": "account", + "path": "user" + } + ] + } + }, + { + "name": "user", + "writable": true, + "signer": true + }, + { + "name": "vault", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 86, + 65, + 85, + 76, + 84 + ] + }, + { + "kind": "account", + "path": "user" + } + ] + } + }, + { + "name": "payer", + "writable": true, + "signer": true + }, + { + "name": "systemProgram", + "address": "11111111111111111111111111111111" + } + ], + "args": [ + { + "name": "amount", + "type": "u64" + } + ] + } + ], + "accounts": [ + { + "name": "globalAccount", + "discriminator": [ + 129, + 105, + 124, + 171, + 189, + 42, + 108, + 69 + ] + }, + { + "name": "lockAccount", + "discriminator": [ + 223, + 64, + 71, + 124, + 255, + 86, + 118, + 192 + ] + }, + { + "name": "userAccount", + "discriminator": [ + 211, + 33, + 136, + 16, + 186, + 110, + 242, + 127 + ] + } + ], + "errors": [ + { + "code": 6000, + "name": "unauthorized", + "msg": "Unauthorized access." + }, + { + "code": 6001, + "name": "insufficientFunds", + "msg": "Insufficient funds." + }, + { + "code": 6002, + "name": "signatureFormatInvalid", + "msg": "The signature format or recovery ID is incorrect." + }, + { + "code": 6003, + "name": "signatureRecoveryFailed", + "msg": "Failed to recover public key from signature." + }, + { + "code": 6004, + "name": "signatureMismatch", + "msg": "The recovered public key does not match the user's public key." + }, + { + "code": 6005, + "name": "signatureExpired", + "msg": "The signature is expired." + } + ], + "types": [ + { + "name": "ed25519RecoverInfo", + "type": { + "kind": "struct", + "fields": [ + { + "name": "signature", + "type": { + "array": [ + "u8", + 64 + ] + } + }, + { + "name": "payload", + "type": { + "array": [ + "u8", + 64 + ] + } + }, + { + "name": "deadline", + "type": "i64" + } + ] + } + }, + { + "name": "globalAccount", + "type": { + "kind": "struct", + "fields": [ + { + "name": "authority", + "type": "pubkey" + }, + { + "name": "bot", + "type": "pubkey" + }, + { + "name": "treasury", + "type": "pubkey" + } + ] + } + }, + { + "name": "lockAccount", + "type": { + "kind": "struct", + "fields": [ + { + "name": "amount", + "type": "u64" + } + ] + } + }, + { + "name": "userAccount", + "type": { + "kind": "struct", + "fields": [ + { + "name": "nonce", + "type": "u64" + }, + { + "name": "lockedAmount", + "type": "u64" + }, + { + "name": "vault", + "type": "pubkey" + } + ] + } + } + ] +}; diff --git a/dephy-vending_machine-examples/balance-payment/bot_example_js/bin/eligible-checker b/dephy-vending_machine-examples/balance-payment/bot_example_js/bin/eligible-checker new file mode 100755 index 0000000..5ec95d3 --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/bot_example_js/bin/eligible-checker @@ -0,0 +1,8 @@ +#!/bin/bash + +USER=$1 +AMOUNT=$2 +NONCE=$3 +RECOVER_INFO=$4 + +exec bun run /opt/balance-payment-bot/index.ts check_eligible --net devnet --rpc "https://api.devnet.solana.com" --user "$USER" --amount "$AMOUNT" --nonce "$NONCE" --recoverInfo "$RECOVER_INFO" diff --git a/dephy-vending_machine-examples/balance-payment/bot_example_js/bin/locker b/dephy-vending_machine-examples/balance-payment/bot_example_js/bin/locker new file mode 100755 index 0000000..765c2c2 --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/bot_example_js/bin/locker @@ -0,0 +1,7 @@ +#!/bin/bash + +USER=$1 +AMOUNT=$2 +RECOVER_INFO=$3 + +exec bun run /opt/balance-payment-bot/index.ts lock --net devnet --rpc "https://api.devnet.solana.com" --keypair /opt/balance-payment-bot/bot.demo.json --user "$USER" --amount "$AMOUNT" --recoverInfo "$RECOVER_INFO" diff --git a/dephy-vending_machine-examples/balance-payment/bot_example_js/bin/settler b/dephy-vending_machine-examples/balance-payment/bot_example_js/bin/settler new file mode 100755 index 0000000..7ccab28 --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/bot_example_js/bin/settler @@ -0,0 +1,7 @@ +#!/bin/bash + +USER=$1 +NONCE=$2 +AMOUNT_TO_TRANSFER=$3 + +exec bun run /opt/balance-payment-bot/index.ts settle --net devnet --rpc "https://api.devnet.solana.com" --keypair /opt/balance-payment-bot/bot.demo.json --user "$USER" --nonce "$NONCE" --amountToTransfer "$AMOUNT_TO_TRANSFER" diff --git a/dephy-vending_machine-examples/balance-payment/bot_example_js/index.ts b/dephy-vending_machine-examples/balance-payment/bot_example_js/index.ts new file mode 100644 index 0000000..eb62492 --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/bot_example_js/index.ts @@ -0,0 +1,618 @@ +import * as anchor from "@coral-xyz/anchor"; +import * as ed from "@noble/ed25519"; +import { web3, Program, BN } from "@coral-xyz/anchor"; +import { BalancePayment } from "./balance_payment"; +import BalancePaymentIDL from "./balance_payment.json"; +import { Command } from "commander"; +import { v4 as uuidv4 } from "uuid"; +import { + Connection, + Keypair, + SendTransactionError, + TransactionExpiredTimeoutError, +} from "@solana/web3.js"; +import keccak from "keccak"; +import { readFileSync } from "fs"; +import os from "os"; +import path from "path"; +import bs58 from "bs58"; + +const cli = new Command(); + +const initializeProviderAndProgram = ( + net: string, + rpc?: string, + keypairPath?: string +) => { + if (net !== "devnet" && net !== "mainnet-beta") { + throw new Error("net must be devnet or mainnet-beta"); + } + + const rpcEndpoint = rpc ?? web3.clusterApiUrl(net); + const connection = new web3.Connection(rpcEndpoint, "confirmed"); + + let provider: anchor.Provider; + let keypair: web3.Keypair | null = null; + + if (keypairPath) { + keypair = getKeypair(keypairPath); + const wallet = new anchor.Wallet(keypair); + provider = new anchor.AnchorProvider(connection, wallet, { + commitment: "confirmed", + }); + } else { + provider = new anchor.AnchorProvider(connection, {} as anchor.Wallet, { + commitment: "confirmed", + }); + } + + anchor.setProvider(provider); + + const program = new Program( + { + ...BalancePaymentIDL, + address: BalancePaymentIDL.address, + } as BalancePayment, + provider + ); + + return { + keypair, // 如果没有 keypairPath,这里会返回 null + provider, + program, + }; +}; + +type Methods = anchor.Program["methods"]; + +const execute = async (tx: ReturnType) => { + const pubkeys = await tx.pubkeys(); + for (const [name, key] of Object.entries(pubkeys)) { + console.log(name, key.toBase58()); + } + const signature = await tx.rpc(); + console.log("signature", signature); + return { signature, pubkeys }; +}; + +const sol = (n: number | string) => { + return new BN(Number(n) * web3.LAMPORTS_PER_SOL); +}; + +const generate64ByteUUIDPayload = (): Buffer => { + const uuid = uuidv4().replace(/-/g, ""); + const uuidBuffer = Buffer.from(uuid, "hex"); + const extendedBuffer = Buffer.concat([uuidBuffer, Buffer.alloc(48, 0)]); + return extendedBuffer; +}; + +const getKeypair = (keypairPath?: string): Keypair => { + // Default path: ~/.config/solana/id.json + const defaultPath = path.join(os.homedir(), ".config", "solana", "id.json"); + const resolvedPath = keypairPath || defaultPath; + + try { + const keypairFile = readFileSync(resolvedPath, "utf-8"); + const keypair = Keypair.fromSecretKey(Buffer.from(JSON.parse(keypairFile))); + return keypair; + } catch (error) { + throw new Error( + `Failed to load keypair from ${resolvedPath}: ${error.message}` + ); + } +}; + +const getUserAccountPubkey = (user: web3.PublicKey) => { + const [userAccountPubkey, _] = web3.PublicKey.findProgramAddressSync( + [Buffer.from("USER"), user.toBuffer()], + new web3.PublicKey(BalancePaymentIDL.address) + ); + return userAccountPubkey; +}; + +async function confirmTransaction(connection, txHash) { + const maxRetries = 10; + const retryInterval = 3000; + + for (let i = 0; i < maxRetries; i++) { + const status = await connection.getSignatureStatus(txHash); + if ( + status && + status.value && + status.value.confirmationStatus === "finalized" + ) { + return "finalized"; + } + console.log( + `Transaction not finalized yet. Retrying in ${ + retryInterval / 1000 + } seconds...` + ); + await sleep(retryInterval); + } + + return "failed"; +} + +function sleep(ms: number) { + return new Promise((resolve) => setTimeout(resolve, ms)); +} + +const SUCCESS = 0; +const NETWORK_ERROR = 1; +const PARAMS_ERROR = 11; +const TRANSACTION_SEND_ERROR = 101; +const TRANSACTION_NOT_CONFIRMED = 102; +const TRANSACTION_UNKNOWN_ERROR = 103; + +const SIGN_MESSAGE_PREFIX = "DePHY vending machine/Example:\n"; + +cli.name("cli"); + +cli + .command("sign_message") + .requiredOption("--net ", "devnet | mainnet-beta") + .option("--rpc ", "rpc url link") + .requiredOption( + "--keypair ", + "Path to keypair file (default: ~/.config/solana/id.json)" + ) + .requiredOption("--minutes ", "Minutes until deadline") + .action(async (opt) => { + const { keypair: userKeypair, program } = initializeProviderAndProgram( + opt.net, + opt.rpc, + opt.keypair + ); + + const user = userKeypair.publicKey; // Use the public key from the provided keypair + + // Log the user who is signing + console.log("Signing user:", user.toBase58()); + + // Get nonce from user account + const userAccountPubkey = getUserAccountPubkey(user); + const userAccount = await program.account.userAccount.fetch( + userAccountPubkey + ); + + console.log("Signing nonce:", userAccount.nonce.toNumber()); + + // Convert minutes to deadline (current timestamp + minutes * 60 seconds) + const currentTimestamp = Math.floor(Date.now() / 1000); + const deadline = new BN(currentTimestamp + Number(opt.minutes) * 60); + + // Generate payload + const payload = generate64ByteUUIDPayload(); + + // Create message + const message = Buffer.concat([ + payload, + userAccount.nonce.toArrayLike(Buffer, "le", 8), + deadline.toArrayLike(Buffer, "le", 8), + ]); + + // Hash the message and generate digest + const messageHash = keccak("keccak256").update(message).digest(); + const hashedMessageBase58 = bs58.encode(messageHash); + const digest = new TextEncoder().encode( + `${SIGN_MESSAGE_PREFIX}${hashedMessageBase58}` + ); + + // Get user's private key + const privateKey = userKeypair.secretKey.slice(0, 32); // First 32 bytes are the private key + + // Sign the message + const signature = await ed.signAsync(digest, privateKey); + + // Create recoverInfo + const recoverInfo = { + signature: Array.from(signature), + payload: Array.from(payload), + deadline, + }; + + // Output recoverInfo as JSON + const jsonString = JSON.stringify(recoverInfo); + console.log("Recover Info (JSON):", jsonString); + + const base64String = Buffer.from(jsonString).toString("base64"); + console.log("Recover Info (Base64):", base64String); + }); + +cli + .command("check_eligible") + .requiredOption("--net ", "devnet | mainnet-beta") + .option("--rpc ", "rpc url link") + .requiredOption("--user ", "User Pubkey") + .requiredOption("--nonce ", "Nonce from request paylaod") + .requiredOption("--amount ", "Amount in SOL") + .requiredOption("--recoverInfo ", "Recover Info (Base64)") + .action(async (opt) => { + const check = async (opt) => { + try { + const lockAmount = sol(opt.amount); + const recoverInfo = JSON.parse( + Buffer.from(opt.recoverInfo, "base64").toString() + ); + const userPubkey = new web3.PublicKey(opt.user); + + const { program, provider } = initializeProviderAndProgram( + opt.net, + opt.rpc, + opt.keypair + ); + + const userAccountPubkey = getUserAccountPubkey(userPubkey); + + const userAccount = await program.account.userAccount.fetch( + userAccountPubkey + ); + + // 0.check nonce from request payload whether equal to nonce on chain + if (userAccount.nonce.toNumber() !== parseInt(opt.nonce, 10)) { + return false; + } + + // 1.concat message, nonce is from blockchain + const message = Buffer.concat([ + Buffer.from(recoverInfo.payload), + userAccount.nonce.toArrayLike(Buffer, "le", 8), + new BN(recoverInfo.deadline, "hex").toArrayLike(Buffer, "le", 8), + ]); + + // 2.hash message and generate digest + const messageHash = keccak("keccak256").update(message).digest(); + const hashedMessageBase58 = bs58.encode(messageHash); + const digest = new TextEncoder().encode( + `${SIGN_MESSAGE_PREFIX}${hashedMessageBase58}` + ); + + // 3.verify signature source + const isValid = await ed.verifyAsync( + Buffer.from(recoverInfo.signature), + digest, + userPubkey.toBytes() + ); + if (!isValid) { + return false; + } + + // 4.verify deadline expiration + const currentTimestamp = Math.floor(Date.now() / 1000); + const deadlineTimestamp = new BN( + recoverInfo.deadline, + "hex" + ).toNumber(); + if (currentTimestamp >= deadlineTimestamp) { + return false; + } + + // 5.verify available balance + const userVaultBalance = new BN( + await provider.connection.getBalance(userAccount.vault) + ); + const availableBalance = userVaultBalance.sub(userAccount.lockedAmount); + if (availableBalance.lt(lockAmount)) { + return false; + } + + return true; + } catch (e) { + console.error("check eligibility error happened,", e); + return false; + } + }; + const result = await check(opt); + console.log(result); + process.exit(result ? 0 : 1); + }); + +cli + .command("lock") + .requiredOption("--net ", "devnet | mainnet-beta") + .option("--rpc ", "rpc url link") + .requiredOption( + "--keypair ", + "Path to keypair file (default: ~/.config/solana/id.json)" + ) + .requiredOption("--user ", "User Pubkey") + .requiredOption("--amount ", "Amount in SOL") + .requiredOption("--recoverInfo ", "Recover Info (Base64)") + .action(async (opt) => { + const { program } = initializeProviderAndProgram( + opt.net, + opt.rpc, + opt.keypair + ); + + let user: web3.PublicKey, nonce: BN, amount: BN, recoverInfo: any; + try { + user = new web3.PublicKey(opt.user); + nonce = new BN(opt.nonce); + amount = sol(opt.amount); + recoverInfo = JSON.parse( + Buffer.from(opt.recoverInfo, "base64").toString() + ); + } catch (error) { + console.error("Parameter parsing error:", error); + process.exit(PARAMS_ERROR); // 参数解析错误 + } + + // 处理 recoverInfo + try { + recoverInfo.signature = Array.from(recoverInfo.signature); + recoverInfo.payload = Array.from(recoverInfo.payload); + recoverInfo.deadline = new BN(recoverInfo.deadline, "hex"); + } catch (error) { + console.error("RecoverInfo parsing error:", error); + process.exit(PARAMS_ERROR); // 参数解析错误 + } + + const [globalAccountPubkey] = web3.PublicKey.findProgramAddressSync( + [Buffer.from("GLOBAL")], + program.programId + ); + let globalAccount: any; + try { + globalAccount = await program.account.globalAccount.fetch( + globalAccountPubkey + ); + } catch (error) { + console.error("Failed to fetch global account:", error); + process.exit(NETWORK_ERROR); // 网络或账户获取错误 + } + + const tx = program.methods.lock(recoverInfo, amount).accountsPartial({ + user, + bot: globalAccount.bot, + }); + + try { + await execute(tx); + console.log("Lock transaction completed successfully."); + } catch (error) { + if (error instanceof SendTransactionError) { + console.error("Smart contract reverted:", error); + process.exit(TRANSACTION_SEND_ERROR); // 交易发送失败 + } else if (error instanceof TransactionExpiredTimeoutError) { + const txHash = error.signature; + console.log( + `Transaction expired but may have succeeded. Checking status for tx hash: ${txHash}` + ); + + const connection = new Connection( + opt.rpc || "https://api.devnet.solana.com" + ); + const status = await confirmTransaction(connection, txHash); + + if (status === "finalized") { + console.log("Transaction finalized successfully."); + } else { + console.error("Transaction failed or could not be finalized."); + process.exit(TRANSACTION_NOT_CONFIRMED); + } + } else { + console.error("Error during lock transaction:", error); + process.exit(TRANSACTION_UNKNOWN_ERROR); + } + } + + process.exit(SUCCESS); + }); + +cli + .command("settle") + .requiredOption("--net ", "devnet | mainnet-beta") + .option("--rpc ", "rpc url link") + .requiredOption( + "--keypair ", + "Path to keypair file (default: ~/.config/solana/id.json)" + ) + .requiredOption("--user ", "User Pubkey") + .requiredOption("--nonce ", "Nonce") + .requiredOption("--amountToTransfer ", "Amount in SOL") + .action(async (opt) => { + const { program } = initializeProviderAndProgram( + opt.net, + opt.rpc, + opt.keypair + ); + + let user: web3.PublicKey, nonce: BN, amountToTransfer: BN; + try { + user = new web3.PublicKey(opt.user); + nonce = new BN(opt.nonce); + amountToTransfer = sol(opt.amountToTransfer); + } catch (error) { + console.error("Parameter parsing error:", error); + process.exit(PARAMS_ERROR); + } + + let globalAccountPubkey: web3.PublicKey, globalAccount: any; + try { + [globalAccountPubkey] = web3.PublicKey.findProgramAddressSync( + [Buffer.from("GLOBAL")], + program.programId + ); + globalAccount = await program.account.globalAccount.fetch( + globalAccountPubkey + ); + } catch (error) { + console.error("Failed to fetch global account:", error); + process.exit(NETWORK_ERROR); + } + + let userAccountPubkey: web3.PublicKey, userAccount: any; + try { + userAccountPubkey = getUserAccountPubkey(userAccountPubkey); + userAccount = await program.account.userAccount.fetch(userAccountPubkey); + } catch (error) { + console.error("Failed to fetch user account:", error); + process.exit(NETWORK_ERROR); + } + + if (nonce.gte(userAccount.nonce)) { + console.error( + `nonce too large: ${nonce.toNumber()} >= ${userAccount.nonce.toNumber()}}` + ); + process.exit(PARAMS_ERROR); + } + + const [lockAccountPubkey] = web3.PublicKey.findProgramAddressSync( + [ + Buffer.from("LOCK"), + user.toBuffer(), + nonce.toArrayLike(Buffer, "le", 8), + ], + program.programId + ); + try { + await program.account.lockAccount.fetch(lockAccountPubkey); + } catch (error) { + if ( + error.message.includes("Account does not exist") && + nonce.lt(userAccount.nonce) + ) { + console.log("Lock already been settled"); + process.exit(SUCCESS); + } else { + console.error("Fetch lock account error:", error); + process.exit(NETWORK_ERROR); + } + } + + const tx = program.methods.settle(nonce, amountToTransfer).accountsPartial({ + user, + treasury: globalAccount.treasury, + bot: globalAccount.bot, + }); + + try { + await execute(tx); + console.log("Settle transaction completed successfully."); + } catch (error) { + if (error instanceof SendTransactionError) { + console.error("Smart contract reverted:", error); + process.exit(TRANSACTION_SEND_ERROR); + } else if (error instanceof TransactionExpiredTimeoutError) { + const txHash = error.signature; + console.log( + `Transaction expired but may have succeeded. Checking status for tx hash: ${txHash}` + ); + + const connection = new Connection( + opt.rpc || "https://api.devnet.solana.com" + ); + const status = await confirmTransaction(connection, txHash); + + if (status === "finalized") { + console.log("Transaction finalized successfully."); + } else { + console.error("Transaction failed or could not be finalized."); + process.exit(TRANSACTION_NOT_CONFIRMED); // 返回非零退出码表示失败 + } + } else { + console.error("Error during settle transaction:", error); + process.exit(TRANSACTION_UNKNOWN_ERROR); // 返回非零退出码表示失败 + } + } + + process.exit(SUCCESS); + }); + +cli + .command("pay") + .requiredOption("--net ", "devnet | mainnet-beta") + .option("--rpc ", "rpc url link") + .requiredOption( + "--keypair ", + "Path to keypair file (default: ~/.config/solana/id.json)" + ) + .requiredOption("--user ", "User Pubkey") + .requiredOption("--amountToTransfer ", "Amount in SOL") + .requiredOption("--recoverInfo ", "Recover Info (Base64)") + .action(async (opt) => { + const { program } = initializeProviderAndProgram( + opt.net, + opt.rpc, + opt.keypair + ); + + let user: web3.PublicKey, nonce: BN, amountToTransfer: BN, recoverInfo: any; + try { + user = new web3.PublicKey(opt.user); + nonce = new BN(opt.nonce); + amountToTransfer = sol(opt.amountToTransfer); + recoverInfo = JSON.parse( + Buffer.from(opt.recoverInfo, "base64").toString() + ); + } catch (error) { + console.error("Parameter parsing error:", error); + process.exit(PARAMS_ERROR); // 参数解析错误 + } + + // 处理 recoverInfo + try { + recoverInfo.signature = Array.from(recoverInfo.signature); + recoverInfo.payload = Array.from(recoverInfo.payload); + recoverInfo.deadline = new BN(recoverInfo.deadline, "hex"); + } catch (error) { + console.error("RecoverInfo parsing error:", error); + process.exit(PARAMS_ERROR); // 参数解析错误 + } + + const [globalAccountPubkey] = web3.PublicKey.findProgramAddressSync( + [Buffer.from("GLOBAL")], + program.programId + ); + let globalAccount: any; + try { + globalAccount = await program.account.globalAccount.fetch( + globalAccountPubkey + ); + } catch (error) { + console.error("Failed to fetch global account:", error); + process.exit(NETWORK_ERROR); // 网络或账户获取错误 + } + + const tx = program.methods.pay(recoverInfo, amountToTransfer).accountsPartial({ + user, + treasury: globalAccount.treasury, + bot: globalAccount.bot, + }); + + try { + await execute(tx); + console.log("Pay transaction completed successfully."); + } catch (error) { + if (error instanceof SendTransactionError) { + console.error("Smart contract reverted:", error); + process.exit(TRANSACTION_SEND_ERROR); // 交易发送失败 + } else if (error instanceof TransactionExpiredTimeoutError) { + const txHash = error.signature; + console.log( + `Transaction expired but may have succeeded. Checking status for tx hash: ${txHash}` + ); + + const connection = new Connection( + opt.rpc || "https://api.devnet.solana.com" + ); + const status = await confirmTransaction(connection, txHash); + + if (status === "finalized") { + console.log("Transaction finalized successfully."); + } else { + console.error("Transaction failed or could not be finalized."); + process.exit(TRANSACTION_NOT_CONFIRMED); + } + } else { + console.error("Error during lock transaction:", error); + process.exit(TRANSACTION_UNKNOWN_ERROR); + } + } + + process.exit(SUCCESS); + }); + +cli.parse(); diff --git a/dephy-vending_machine-examples/balance-payment/bot_example_js/package.json b/dephy-vending_machine-examples/balance-payment/bot_example_js/package.json new file mode 100644 index 0000000..cd0150b --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/bot_example_js/package.json @@ -0,0 +1,27 @@ +{ + "license": "ISC", + "scripts": { + "lint:fix": "prettier */*.js \"*/**/*{.js,.ts}\" -w", + "lint": "prettier */*.js \"*/**/*{.js,.ts}\" --check" + }, + "dependencies": { + "@coral-xyz/anchor": "^0.31.0", + "@noble/ed25519": "^2.2.2", + "@solana/web3.js": "^1.98.0", + "bs58": "^6.0.0", + "commander": "^13.0.0", + "keccak": "^3.0.4" + }, + "devDependencies": { + "@types/bn.js": "^5.1.0", + "@types/chai": "^4.3.0", + "@types/keccak": "^3.0.5", + "@types/mocha": "^9.0.0", + "@types/secp256k1": "^4.0.6", + "chai": "^4.3.4", + "mocha": "^9.0.3", + "prettier": "^2.6.2", + "ts-mocha": "^10.0.0", + "typescript": "^4.3.5" + } +} diff --git a/dephy-vending_machine-examples/balance-payment/bot_example_js/tsconfig.json b/dephy-vending_machine-examples/balance-payment/bot_example_js/tsconfig.json new file mode 100644 index 0000000..247d160 --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/bot_example_js/tsconfig.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "types": ["mocha", "chai"], + "typeRoots": ["./node_modules/@types"], + "lib": ["es2015"], + "module": "commonjs", + "target": "es6", + "esModuleInterop": true, + "resolveJsonModule": true + } +} diff --git a/dephy-vending_machine-examples/balance-payment/migrations/deploy.ts b/dephy-vending_machine-examples/balance-payment/migrations/deploy.ts new file mode 100644 index 0000000..82fb175 --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/migrations/deploy.ts @@ -0,0 +1,12 @@ +// Migrations are an early feature. Currently, they're nothing more than this +// single deploy script that's invoked from the CLI, injecting a provider +// configured from the workspace's Anchor.toml. + +const anchor = require("@coral-xyz/anchor"); + +module.exports = async function (provider) { + // Configure client to use the provider. + anchor.setProvider(provider); + + // Add your deploy script here. +}; diff --git a/dephy-vending_machine-examples/balance-payment/package.json b/dephy-vending_machine-examples/balance-payment/package.json new file mode 100644 index 0000000..14a4860 --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/package.json @@ -0,0 +1,30 @@ +{ + "license": "ISC", + "scripts": { + "lint:fix": "prettier */*.js \"*/**/*{.js,.ts}\" -w", + "lint": "prettier */*.js \"*/**/*{.js,.ts}\" --check" + }, + "dependencies": { + "@coral-xyz/anchor": "^0.31.0", + "@solana/web3.js": "^1.98.0" + }, + "devDependencies": { + "@noble/ed25519": "^2.2.2", + "@types/bn.js": "^5.1.0", + "@types/chai": "^4.3.0", + "@types/keccak": "^3.0.5", + "@types/mocha": "^9.0.0", + "@types/secp256k1": "^4.0.6", + "bs58": "^6.0.0", + "chai": "^4.3.4", + "commander": "^13.0.0", + "keccak": "^3.0.4", + "mocha": "^9.0.3", + "prettier": "^2.6.2", + "ts-mocha": "^10.0.0", + "typescript": "^4.3.5" + }, + "overrides": { + "@solana/buffer-layout": "^4.0.1" + } +} diff --git a/dephy-vending_machine-examples/balance-payment/programs/balance-payment/Cargo.toml b/dephy-vending_machine-examples/balance-payment/programs/balance-payment/Cargo.toml new file mode 100644 index 0000000..44c9089 --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/programs/balance-payment/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "balance-payment" +version = "0.1.0" +description = "Created with Anchor" +edition = "2021" + +[lib] +crate-type = ["cdylib", "lib"] +name = "balance_payment" + +[features] +default = [] +cpi = ["no-entrypoint"] +no-entrypoint = [] +no-idl = [] +no-log-ix-name = [] +idl-build = ["anchor-lang/idl-build"] + +[dependencies] +anchor-lang = { version = "0.31.0" } +anyhow = "1" +arrayref = "*" +bs58 = "0.4" +curve25519-dalek = { version = "4", default-features = false } +sha2 = "0.10.8" +solana-zk-token-sdk = "^2.0.2" diff --git a/dephy-vending_machine-examples/balance-payment/programs/balance-payment/Xargo.toml b/dephy-vending_machine-examples/balance-payment/programs/balance-payment/Xargo.toml new file mode 100644 index 0000000..475fb71 --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/programs/balance-payment/Xargo.toml @@ -0,0 +1,2 @@ +[target.bpfel-unknown-unknown.dependencies.std] +features = [] diff --git a/dephy-vending_machine-examples/balance-payment/programs/balance-payment/keypair.json b/dephy-vending_machine-examples/balance-payment/programs/balance-payment/keypair.json new file mode 100644 index 0000000..9c16f48 --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/programs/balance-payment/keypair.json @@ -0,0 +1 @@ +[118,171,22,138,219,238,43,55,2,144,166,47,140,179,126,103,91,80,241,45,49,251,228,181,187,228,111,60,141,175,91,161,233,24,77,228,82,49,123,133,27,66,243,147,119,224,89,94,109,109,160,165,223,142,1,104,207,96,236,176,122,11,134,82] diff --git a/dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/constants.rs b/dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/constants.rs new file mode 100644 index 0000000..ccb0955 --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/constants.rs @@ -0,0 +1,2 @@ +pub const DISCRIMINATOR_SIZE: usize = 8; +pub const SIGN_MESSAGE_PREFIX: &[u8; 31] = b"DePHY vending machine/Example:\n"; diff --git a/dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/errors.rs b/dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/errors.rs new file mode 100644 index 0000000..3803c8e --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/errors.rs @@ -0,0 +1,17 @@ +use anchor_lang::error_code; + +#[error_code] +pub enum CustomError { + #[msg("Unauthorized access.")] + Unauthorized, + #[msg("Insufficient funds.")] + InsufficientFunds, + #[msg("The signature format or recovery ID is incorrect.")] + SignatureFormatInvalid, + #[msg("Failed to recover public key from signature.")] + SignatureRecoveryFailed, + #[msg("The recovered public key does not match the user's public key.")] + SignatureMismatch, + #[msg("The signature is expired.")] + SignatureExpired, +} diff --git a/dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/instructions/deposit.rs b/dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/instructions/deposit.rs new file mode 100644 index 0000000..25eb90f --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/instructions/deposit.rs @@ -0,0 +1,33 @@ +use crate::state::UserAccount; +use anchor_lang::{prelude::*, system_program}; + +pub fn deposit(ctx: Context, amount: u64) -> Result<()> { + system_program::transfer( + CpiContext::new_with_signer( + ctx.accounts.system_program.to_account_info(), + system_program::Transfer { + from: ctx.accounts.user.to_account_info(), + to: ctx.accounts.vault.to_account_info(), + }, + &[], + ), + amount, + )?; + + Ok(()) +} + + +#[derive(Accounts)] +pub struct Deposit<'info> { + #[account(mut, seeds = [b"USER", user.key.as_ref()], bump)] + pub user_account: Account<'info, UserAccount>, + #[account(mut)] + pub user: Signer<'info>, + /// CHECK: + #[account(mut, seeds = [b"VAULT", user.key().as_ref()], bump)] + pub vault: UncheckedAccount<'info>, + #[account(mut)] + pub payer: Signer<'info>, + pub system_program: Program<'info, System>, +} diff --git a/dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/instructions/initialize.rs b/dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/instructions/initialize.rs new file mode 100644 index 0000000..7447a96 --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/instructions/initialize.rs @@ -0,0 +1,29 @@ +use crate::constants::DISCRIMINATOR_SIZE; +use crate::state::GlobalAccount; +use anchor_lang::prelude::*; + +pub fn initialize(ctx: Context) -> Result<()> { + let global_account = &mut ctx.accounts.global_account; + global_account.authority = ctx.accounts.authority.key(); + global_account.bot = ctx.accounts.bot.key(); + global_account.treasury = ctx.accounts.treasury.key(); + Ok(()) +} + +#[derive(Accounts)] +pub struct Initialize<'info> { + #[account(init, payer = payer, space = DISCRIMINATOR_SIZE + GlobalAccount::INIT_SPACE, seeds = [b"GLOBAL"], bump)] + pub global_account: Account<'info, GlobalAccount>, + /// CHECK: + #[account(constraint = authority.data_is_empty())] + pub authority: UncheckedAccount<'info>, + /// CHECK: + #[account(constraint = treasury.data_is_empty())] + pub treasury: UncheckedAccount<'info>, + /// CHECK: + #[account(constraint = bot.data_is_empty())] + pub bot: UncheckedAccount<'info>, + #[account(mut)] + pub payer: Signer<'info>, + pub system_program: Program<'info, System>, +} diff --git a/dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/instructions/lock.rs b/dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/instructions/lock.rs new file mode 100644 index 0000000..293b94a --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/instructions/lock.rs @@ -0,0 +1,98 @@ +use crate::{ + constants::{self, DISCRIMINATOR_SIZE}, + errors::CustomError, + state::{GlobalAccount, LockAccount, UserAccount}, + utils, +}; +use anchor_lang::{prelude::*, solana_program::keccak}; +use bs58; + +pub fn lock(ctx: Context, recover_info: ED25519RecoverInfo, amount: u64) -> Result<()> { + let user_account = &mut ctx.accounts.user_account; + let lock_account = &mut ctx.accounts.lock_account; + + recover_info.verify(user_account.nonce, &ctx.accounts.user.key())?; + + require!( + ctx.accounts.vault.get_lamports() - user_account.locked_amount >= amount, + CustomError::InsufficientFunds + ); + + user_account.nonce += 1; + user_account.locked_amount += amount; + + lock_account.amount = amount; + + Ok(()) +} + +#[derive(Accounts)] +pub struct Lock<'info> { + #[account(has_one = bot @ CustomError::Unauthorized, seeds = [b"GLOBAL"], bump)] + pub global_account: Account<'info, GlobalAccount>, + #[account(mut, seeds = [b"USER", user.key.as_ref()], bump)] + pub user_account: Account<'info, UserAccount>, + /// CHECK: + #[account(mut)] + pub user: UncheckedAccount<'info>, + #[account( + init, + payer = payer, + space = DISCRIMINATOR_SIZE + LockAccount::INIT_SPACE, + seeds = [b"LOCK", user.key().as_ref(), user_account.nonce.to_le_bytes().as_ref()], + bump, + )] + pub lock_account: Account<'info, LockAccount>, + /// CHECK: + #[account(seeds = [b"VAULT", user.key().as_ref()], bump)] + pub vault: UncheckedAccount<'info>, + pub bot: Signer<'info>, + #[account(mut)] + pub payer: Signer<'info>, + pub system_program: Program<'info, System>, +} + +#[derive(Debug, Clone, AnchorSerialize, AnchorDeserialize)] +pub struct ED25519RecoverInfo { + pub signature: [u8; 64], + pub payload: [u8; 64], + pub deadline: i64, +} + +impl ED25519RecoverInfo { + pub fn verify(&self, nonce: u64, pubkey: &Pubkey) -> Result<()> { + let message = { + let mut data = self.payload.to_vec(); + data.extend_from_slice(&nonce.to_le_bytes()); + data.extend_from_slice(&self.deadline.to_le_bytes()); + data + }; + + let hashed_message = { + let mut hasher = keccak::Hasher::default(); + hasher.hash(&message); + hasher.result().to_bytes() + }; + + let hashed_message_base58 = bs58::encode(&hashed_message).into_vec(); + + let digest = { + let mut data = constants::SIGN_MESSAGE_PREFIX.to_vec(); // 前缀转换为 Vec + data.extend_from_slice(&hashed_message_base58); // 添加 Base58 编码的哈希值 + data + }; + + let valid = utils::verify_signature(pubkey, &self.signature, &digest) + .map_err(|_| CustomError::SignatureFormatInvalid)?; + + require!(valid, CustomError::SignatureMismatch); + + let clock = Clock::get()?; + require!( + clock.unix_timestamp <= self.deadline, + CustomError::SignatureExpired + ); + + Ok(()) + } +} diff --git a/dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/instructions/mod.rs b/dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/instructions/mod.rs new file mode 100644 index 0000000..77c4668 --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/instructions/mod.rs @@ -0,0 +1,19 @@ +pub mod initialize; +pub mod set_bot; +pub mod set_treasury; +pub mod register; +pub mod deposit; +pub mod withdraw; +pub mod lock; +pub mod settle; +pub mod pay; + +pub use initialize::*; +pub use set_bot::*; +pub use set_treasury::*; +pub use register::*; +pub use deposit::*; +pub use withdraw::*; +pub use lock::*; +pub use settle::*; +pub use pay::*; diff --git a/dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/instructions/pay.rs b/dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/instructions/pay.rs new file mode 100644 index 0000000..121333b --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/instructions/pay.rs @@ -0,0 +1,63 @@ +use crate::{ + errors::CustomError, + state::{GlobalAccount, UserAccount}, +}; +use anchor_lang::{prelude::*, system_program}; + +use super::ED25519RecoverInfo; + +pub fn pay( + ctx: Context, + recover_info: ED25519RecoverInfo, + amount_to_transfer: u64, +) -> Result<()> { + let user_account = &mut ctx.accounts.user_account; + + recover_info.verify(user_account.nonce, &ctx.accounts.user.key())?; + + require!( + ctx.accounts.vault.get_lamports() - user_account.locked_amount >= amount_to_transfer, + CustomError::InsufficientFunds + ); + + system_program::transfer( + CpiContext::new_with_signer( + ctx.accounts.system_program.to_account_info(), + system_program::Transfer { + from: ctx.accounts.vault.to_account_info(), + to: ctx.accounts.treasury.to_account_info(), + }, + &[&[ + b"VAULT", + ctx.accounts.user.key().as_ref(), + &[ctx.bumps.vault], + ]], + ), + amount_to_transfer, + )?; + + user_account.nonce += 1; + + Ok(()) +} + +#[derive(Accounts)] +pub struct Pay<'info> { + #[account(has_one = bot @ CustomError::Unauthorized, seeds = [b"GLOBAL"], bump)] + pub global_account: Account<'info, GlobalAccount>, + #[account(mut, seeds = [b"USER", user.key.as_ref()], bump)] + pub user_account: Account<'info, UserAccount>, + /// CHECK: + #[account(mut)] + pub user: UncheckedAccount<'info>, + /// CHECK: + #[account(mut, constraint = treasury.key() == global_account.treasury)] + pub treasury: UncheckedAccount<'info>, + /// CHECK: + #[account(mut, seeds = [b"VAULT", user.key().as_ref()], bump)] + pub vault: UncheckedAccount<'info>, + pub bot: Signer<'info>, + #[account(mut)] + pub payer: Signer<'info>, + pub system_program: Program<'info, System>, +} diff --git a/dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/instructions/register.rs b/dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/instructions/register.rs new file mode 100644 index 0000000..74ca712 --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/instructions/register.rs @@ -0,0 +1,24 @@ +use crate::constants::DISCRIMINATOR_SIZE; +use crate::state::UserAccount; +use anchor_lang::prelude::*; + +pub fn register(ctx: Context) -> Result<()> { + let user_account = &mut ctx.accounts.user_account; + user_account.nonce = 0; + user_account.locked_amount = 0; + user_account.vault = ctx.accounts.vault.key(); + Ok(()) +} + +#[derive(Accounts)] +pub struct Register<'info> { + #[account(init, payer = payer, space = DISCRIMINATOR_SIZE + UserAccount::INIT_SPACE, seeds = [b"USER", user.key.as_ref()], bump)] + pub user_account: Account<'info, UserAccount>, + pub user: Signer<'info>, + /// CHECK: vault is only used for store SOL + #[account(constraint = vault.data_is_empty(), seeds = [b"VAULT", user.key().as_ref()], bump)] + pub vault: UncheckedAccount<'info>, + #[account(mut)] + pub payer: Signer<'info>, + pub system_program: Program<'info, System>, +} diff --git a/dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/instructions/set_bot.rs b/dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/instructions/set_bot.rs new file mode 100644 index 0000000..923aecb --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/instructions/set_bot.rs @@ -0,0 +1,21 @@ +use crate::errors::CustomError; +use crate::state::GlobalAccount; +use anchor_lang::prelude::*; + +pub fn set_bot(ctx: Context) -> Result<()> { + let global_account = &mut ctx.accounts.global_account; + global_account.bot = ctx.accounts.bot.key(); + Ok(()) +} + +#[derive(Accounts)] +pub struct SetBot<'info> { + #[account(mut, has_one = authority @ CustomError::Unauthorized, seeds = [b"GLOBAL"], bump)] + pub global_account: Account<'info, GlobalAccount>, + pub authority: Signer<'info>, + /// CHECK: + #[account(constraint = bot.data_is_empty())] + pub bot: UncheckedAccount<'info>, + #[account(mut)] + pub payer: Signer<'info>, +} diff --git a/dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/instructions/set_treasury.rs b/dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/instructions/set_treasury.rs new file mode 100644 index 0000000..72a59e3 --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/instructions/set_treasury.rs @@ -0,0 +1,21 @@ +use crate::errors::CustomError; +use crate::state::GlobalAccount; +use anchor_lang::prelude::*; + +pub fn set_treasury(ctx: Context) -> Result<()> { + let global_account = &mut ctx.accounts.global_account; + global_account.treasury = ctx.accounts.treasury.key(); + Ok(()) +} + +#[derive(Accounts)] +pub struct SetTreasury<'info> { + #[account(mut, has_one = authority @ CustomError::Unauthorized, seeds = [b"GLOBAL"], bump)] + pub global_account: Account<'info, GlobalAccount>, + pub authority: Signer<'info>, + /// CHECK: + #[account(constraint = treasury.data_is_empty())] + pub treasury: UncheckedAccount<'info>, + #[account(mut)] + pub payer: Signer<'info>, +} diff --git a/dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/instructions/settle.rs b/dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/instructions/settle.rs new file mode 100644 index 0000000..7c3370d --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/instructions/settle.rs @@ -0,0 +1,75 @@ +use crate::{ + errors::CustomError, + state::{GlobalAccount, LockAccount, UserAccount}, +}; +use anchor_lang::{prelude::*, system_program}; + +pub fn settle(ctx: Context, _nonce: u64, amount_to_transfer: u64) -> Result<()> { + let user_account = &mut ctx.accounts.user_account; + let lock_account = &mut ctx.accounts.lock_account; + + require!( + lock_account.amount >= amount_to_transfer, + CustomError::InsufficientFunds + ); + + user_account.locked_amount -= lock_account.amount; + + system_program::transfer( + CpiContext::new_with_signer( + ctx.accounts.system_program.to_account_info(), + system_program::Transfer { + from: ctx.accounts.vault.to_account_info(), + to: ctx.accounts.treasury.to_account_info(), + }, + &[&[ + b"VAULT", + ctx.accounts.user.key().as_ref(), + &[ctx.bumps.vault], + ]], + ), + amount_to_transfer, + )?; + + // Close the lock account and transfer the rent to the payer + let lock_account_info = lock_account.to_account_info(); + let payer_info = ctx.accounts.payer.to_account_info(); + let rent = Rent::get()?; + let lamports = rent.minimum_balance(lock_account_info.data_len()); + + **lock_account_info.lamports.borrow_mut() -= lamports; + **payer_info.lamports.borrow_mut() += lamports; + + lock_account_info.assign(&system_program::ID); + lock_account_info.realloc(0, false)?; + + Ok(()) +} + +#[derive(Accounts)] +#[instruction(nonce: u64)] +pub struct Settle<'info> { + #[account(has_one = bot @ CustomError::Unauthorized, seeds = [b"GLOBAL"], bump)] + pub global_account: Account<'info, GlobalAccount>, + #[account(mut, seeds = [b"USER", user.key.as_ref()], bump)] + pub user_account: Account<'info, UserAccount>, + /// CHECK: + #[account(mut)] + pub user: UncheckedAccount<'info>, + /// CHECK: + #[account(mut, constraint = treasury.key() == global_account.treasury)] + pub treasury: UncheckedAccount<'info>, + #[account( + mut, + seeds = [b"LOCK", user.key().as_ref(), nonce.to_le_bytes().as_ref()], + bump, + )] + pub lock_account: Account<'info, LockAccount>, + /// CHECK: + #[account(mut, seeds = [b"VAULT", user.key().as_ref()], bump)] + pub vault: UncheckedAccount<'info>, + pub bot: Signer<'info>, + #[account(mut)] + pub payer: Signer<'info>, + pub system_program: Program<'info, System>, +} diff --git a/dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/instructions/withdraw.rs b/dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/instructions/withdraw.rs new file mode 100644 index 0000000..a15e2c8 --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/instructions/withdraw.rs @@ -0,0 +1,40 @@ +use crate::{errors::CustomError, state::UserAccount}; +use anchor_lang::{prelude::*, system_program}; + +pub fn withdraw(ctx: Context, amount: u64) -> Result<()> { + let available_balance = + ctx.accounts.vault.get_lamports() - ctx.accounts.user_account.locked_amount; + require!(available_balance >= amount, CustomError::InsufficientFunds); + + system_program::transfer( + CpiContext::new_with_signer( + ctx.accounts.system_program.to_account_info(), + system_program::Transfer { + from: ctx.accounts.vault.to_account_info(), + to: ctx.accounts.user.to_account_info(), + }, + &[&[ + b"VAULT", + ctx.accounts.user.key().as_ref(), + &[ctx.bumps.vault], + ]], + ), + amount, + )?; + + Ok(()) +} + +#[derive(Accounts)] +pub struct Withdraw<'info> { + #[account(mut, seeds = [b"USER", user.key.as_ref()], bump)] + pub user_account: Account<'info, UserAccount>, + #[account(mut)] + pub user: Signer<'info>, + /// CHECK: + #[account(mut, seeds = [b"VAULT", user.key().as_ref()], bump)] + pub vault: UncheckedAccount<'info>, + #[account(mut)] + pub payer: Signer<'info>, + pub system_program: Program<'info, System>, +} diff --git a/dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/lib.rs b/dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/lib.rs new file mode 100644 index 0000000..bde08a6 --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/lib.rs @@ -0,0 +1,52 @@ +use anchor_lang::prelude::*; + +pub mod constants; +pub mod errors; +pub mod instructions; +pub mod state; +pub mod utils; + +use instructions::*; + +declare_id!("GguVKxU88NUe3GLtns7Uaa6a8Pjb9USKq3WD1rjZnPS9"); + +#[program] +pub mod balance_payment { + use super::*; + + pub fn initialize(ctx: Context) -> Result<()> { + instructions::initialize(ctx) + } + + pub fn set_bot(ctx: Context) -> Result<()> { + instructions::set_bot(ctx) + } + + pub fn set_treasury(ctx: Context) -> Result<()> { + instructions::set_treasury(ctx) + } + + pub fn register(ctx: Context) -> Result<()> { + instructions::register(ctx) + } + + pub fn deposit(ctx: Context, amount: u64) -> Result<()> { + instructions::deposit(ctx, amount) + } + + pub fn withdraw(ctx: Context, amount: u64) -> Result<()> { + instructions::withdraw(ctx, amount) + } + + pub fn lock(ctx: Context, recover_info: ED25519RecoverInfo, amount: u64) -> Result<()> { + instructions::lock(ctx, recover_info, amount) + } + + pub fn settle(ctx: Context, _nonce: u64, amount_to_transfer: u64) -> Result<()> { + instructions::settle(ctx, _nonce, amount_to_transfer) + } + + pub fn pay(ctx: Context, recover_info: ED25519RecoverInfo, amount_to_transfer: u64) -> Result<()> { + instructions::pay(ctx, recover_info, amount_to_transfer) + } +} diff --git a/dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/state/global.rs b/dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/state/global.rs new file mode 100644 index 0000000..1fd8374 --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/state/global.rs @@ -0,0 +1,9 @@ +use anchor_lang::prelude::*; + +#[account] +#[derive(InitSpace)] +pub struct GlobalAccount { + pub authority: Pubkey, + pub bot: Pubkey, + pub treasury: Pubkey, +} diff --git a/dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/state/lock.rs b/dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/state/lock.rs new file mode 100644 index 0000000..454eb33 --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/state/lock.rs @@ -0,0 +1,7 @@ +use anchor_lang::prelude::*; + +#[account] +#[derive(InitSpace)] +pub struct LockAccount { + pub amount: u64, +} diff --git a/dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/state/mod.rs b/dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/state/mod.rs new file mode 100644 index 0000000..892ebc5 --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/state/mod.rs @@ -0,0 +1,7 @@ +pub mod global; +pub mod user; +pub mod lock; + +pub use global::*; +pub use user::*; +pub use lock::*; diff --git a/dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/state/user.rs b/dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/state/user.rs new file mode 100644 index 0000000..89cac1e --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/state/user.rs @@ -0,0 +1,9 @@ +use anchor_lang::prelude::*; + +#[account] +#[derive(InitSpace)] +pub struct UserAccount { + pub nonce: u64, + pub locked_amount: u64, + pub vault: Pubkey, +} diff --git a/dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/utils/ed25519.rs b/dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/utils/ed25519.rs new file mode 100644 index 0000000..24e17c5 --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/utils/ed25519.rs @@ -0,0 +1,51 @@ +// from https://github.com/stegaBOB/solana_ed25519_verify/blob/main/src/lib.rs + +use anchor_lang::solana_program::pubkey::Pubkey; +use anyhow::{bail, Context}; +use arrayref::array_ref; +use curve25519_dalek::scalar::Scalar; +use sha2::Digest; +use solana_zk_token_sdk::curve25519::{ + edwards::{multiply_edwards, subtract_edwards, validate_edwards, PodEdwardsPoint}, + scalar::PodScalar, +}; + +// funny number +const EDWARDS_BASE_POINT: PodEdwardsPoint = PodEdwardsPoint([ + 0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, +]); + +pub fn verify_signature( + pubkey: &Pubkey, + signature: &[u8; 64], + message: &[u8], +) -> anyhow::Result { + let a = PodEdwardsPoint(pubkey.to_bytes()); + let r = PodEdwardsPoint(*array_ref![signature, 0, 32]); + if !validate_edwards(&a) { + bail!("Pubkey is not a valid EdwardsPoint") + } + if !validate_edwards(&r) { + bail!("Signature R is not a valid EdwardsPoint") + } + + let s = array_ref![signature, 32, 32]; + let s_scalar = Scalar::from_bytes_mod_order(*s); + let s_scalar = PodScalar(s_scalar.to_bytes()); + + let mut hasher = sha2::Sha512::new(); + // R || A || M + hasher.update(r.0); + hasher.update(a.0); + hasher.update(message); + let hash_bytes = hasher.finalize(); + let hash_array = array_ref![hash_bytes, 0, 64]; + let h_scalar = Scalar::from_bytes_mod_order_wide(hash_array); + let h_scalar = PodScalar(h_scalar.to_bytes()); + + let s_b = multiply_edwards(&s_scalar, &EDWARDS_BASE_POINT).context("Failed to multiply S*B")?; + let h_a = multiply_edwards(&h_scalar, &a).context("Failed to multiply H*A")?; + let r_prime = subtract_edwards(&s_b, &h_a).context("Failed to subtract HA from SB")?; + Ok(r_prime == r) +} diff --git a/dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/utils/mod.rs b/dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/utils/mod.rs new file mode 100644 index 0000000..da1d6fe --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/programs/balance-payment/src/utils/mod.rs @@ -0,0 +1,3 @@ +pub mod ed25519; + +pub use ed25519::*; diff --git a/dephy-vending_machine-examples/balance-payment/scripts/cli.ts b/dephy-vending_machine-examples/balance-payment/scripts/cli.ts new file mode 100644 index 0000000..1d27fee --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/scripts/cli.ts @@ -0,0 +1,354 @@ +import * as anchor from "@coral-xyz/anchor"; +import * as ed from "@noble/ed25519"; +import { web3, Program, BN } from "@coral-xyz/anchor"; +import { BalancePayment } from "../target/types/balance_payment"; +import { Command } from "commander"; +import { Keypair } from "@solana/web3.js"; +import { v4 as uuidv4 } from "uuid"; +import keccak from "keccak"; +import { readFileSync } from "fs"; +import bs58 from "bs58"; +import os from "os"; +import path from "path"; + +const SIGN_MESSAGE_PREFIX = "DePHY vending machine/Example:\n"; + +const cli = new Command(); + +let provider: anchor.AnchorProvider; +const getBalancePaymentProgram = () => { + provider = anchor.AnchorProvider.env(); + anchor.setProvider(provider); + return anchor.workspace.BalancePayment as Program; +}; + +type Methods = anchor.Program["methods"]; + +const execute = async (tx: ReturnType) => { + const pubkeys = await tx.pubkeys(); + for (const [name, key] of Object.entries(pubkeys)) { + console.log(name, key.toBase58()); + } + const signature = await tx.rpc(); + console.log("signature", signature); + return { signature, pubkeys }; +}; + +const sol = (n: number | string) => { + return new BN(Number(n) * web3.LAMPORTS_PER_SOL); +}; + +const showObj = ( + obj: { [_: string]: web3.PublicKey | BN | any }, + indent = 0 +) => { + const padding = " ".repeat(indent); + for (const [k, v] of Object.entries(obj)) { + if (BN.isBN(v)) { + console.log(padding, k, v.toNumber()); + } else if (v?.toBase58) { + console.log(padding, k, v.toBase58()); + } else if (v && typeof v === "object") { + console.log(padding, k); + showObj(v, indent + 2); + } else { + console.log(padding, k, v); + } + } +}; + +const getUserKeypair = (keypairPath?: string): Keypair => { + // Default path: ~/.config/solana/id.json + const defaultPath = path.join(os.homedir(), ".config", "solana", "id.json"); + const resolvedPath = keypairPath || defaultPath; + + try { + const keypairFile = readFileSync(resolvedPath, "utf-8"); + const keypair = Keypair.fromSecretKey(Buffer.from(JSON.parse(keypairFile))); + return keypair; + } catch (error) { + throw new Error( + `Failed to load keypair from ${resolvedPath}: ${error.message}` + ); + } +}; + +const generate64ByteUUIDPayload = (): Buffer => { + const uuid = uuidv4().replace(/-/g, ""); + const uuidBuffer = Buffer.from(uuid, "hex"); + const extendedBuffer = Buffer.concat([uuidBuffer, Buffer.alloc(48, 0)]); + return extendedBuffer; +}; + +const getNonce = async (user: web3.PublicKey): Promise => { + const balancePayment = getBalancePaymentProgram(); + const userAccountPubkey = getUserAccountPubkey(user); + const userAccount = await balancePayment.account.userAccount.fetch( + userAccountPubkey + ); + return userAccount.nonce; +}; + +const getUserAccountPubkey = (user: web3.PublicKey) => { + const [userAccountPubkey, _] = web3.PublicKey.findProgramAddressSync( + [Buffer.from("USER"), user.toBuffer()], + anchor.workspace.BalancePayment.programId + ); + return userAccountPubkey; +}; + +cli.name("cli"); + +cli + .command("initialize") + .requiredOption("--authority ", "Pubkey") + .requiredOption("--treasury ", "Pubkey") + .requiredOption("--bot ", "Pubkey") + .action(async (opt) => { + const payfiPool = getBalancePaymentProgram(); + const tx = payfiPool.methods.initialize().accountsPartial({ + authority: new web3.PublicKey(opt.authority), + treasury: new web3.PublicKey(opt.treasury), + bot: new web3.PublicKey(opt.bot), + }); + await execute(tx); + }); + +cli + .command("set_treasury") + .requiredOption("--treasury ", "Pubkey") + .action(async (opt) => { + const balancePayment = getBalancePaymentProgram(); + const authority = provider.publicKey; + const tx = balancePayment.methods.setTreasury().accountsPartial({ + authority, + treasury: new web3.PublicKey(opt.treasury), + }); + await execute(tx); + }); + +cli + .command("set_bot") + .requiredOption("--bot ", "Pubkey") + .action(async (opt) => { + const balancePayment = getBalancePaymentProgram(); + const authority = provider.publicKey; + const tx = balancePayment.methods.setBot().accountsPartial({ + authority, + bot: new web3.PublicKey(opt.bot), + }); + await execute(tx); + }); + +cli.command("register").action(async () => { + const balancePayment = getBalancePaymentProgram(); + const user = provider.publicKey; + const tx = balancePayment.methods.register().accountsPartial({ + user, + }); + await execute(tx); +}); + +cli + .command("deposit") + .requiredOption("--amount ", "Amount in SOL") + .action(async (opt) => { + const balancePayment = getBalancePaymentProgram(); + const user = provider.publicKey; + const amount = sol(opt.amount); + const tx = balancePayment.methods.deposit(amount).accountsPartial({ + user, + }); + await execute(tx); + }); + +cli + .command("withdraw") + .requiredOption("--amount ", "Amount in SOL") + .action(async (opt) => { + const balancePayment = getBalancePaymentProgram(); + const user = provider.publicKey; + const amount = sol(opt.amount); + const tx = balancePayment.methods.withdraw(amount).accountsPartial({ + user, + }); + await execute(tx); + }); + +cli + .command("sign_message") + .requiredOption("--minutes ", "Minutes until deadline") + .option( + "--keypair ", + "Path to keypair file (default: ~/.config/solana/id.json)" + ) + .action(async (opt) => { + // Get user's keypair + const userKeypair = getUserKeypair(opt.keypair); + const user = userKeypair.publicKey; // Use the public key from the provided keypair + + // Log the user who is signing + console.log("Signing user:", user.toBase58()); + + // Get nonce from user account + const nonce = await getNonce(user); + + // Convert minutes to deadline (current timestamp + minutes * 60 seconds) + const currentTimestamp = Math.floor(Date.now() / 1000); + const deadline = new BN(currentTimestamp + Number(opt.minutes) * 60); + + // Generate payload + const payload = generate64ByteUUIDPayload(); + + // Create message + const message = Buffer.concat([ + payload, + nonce.toArrayLike(Buffer, "le", 8), + deadline.toArrayLike(Buffer, "le", 8), + ]); + + // Hash the message and generate digest + const messageHash = keccak("keccak256").update(message).digest(); + const hashedMessageBase58 = bs58.encode(messageHash); + const digest = new TextEncoder().encode(`${SIGN_MESSAGE_PREFIX}${hashedMessageBase58}`); + + // Get user's private key + const privateKey = userKeypair.secretKey.slice(0, 32); // First 32 bytes are the private key + + // Sign the message + const signature = await ed.signAsync(digest, privateKey); + + // Create recoverInfo + const recoverInfo = { + signature: Array.from(signature), + payload: Array.from(payload), + deadline, + }; + + // Output recoverInfo as JSON + const jsonString = JSON.stringify(recoverInfo); + console.log("Recover Info (JSON):", jsonString); + + const base64String = Buffer.from(jsonString).toString("base64"); + console.log("Recover Info (Base64)", base64String); + }); + +cli + .command("lock") + .requiredOption("--user ", "User Pubkey") + .requiredOption("--amount ", "Amount in SOL") + .requiredOption("--recoverInfo ", "Recover Info (Base64)") + .action(async (opt) => { + const balancePayment = getBalancePaymentProgram(); + const user = new web3.PublicKey(opt.user); + const amount = sol(opt.amount); + const recoverInfo = JSON.parse( + Buffer.from(opt.recoverInfo, "base64").toString() + ); + + recoverInfo.signature = Array.from(recoverInfo.signature); + recoverInfo.payload = Array.from(recoverInfo.payload); + recoverInfo.deadline = new BN(recoverInfo.deadline, "hex"); + + const [globalAccountPubkey, _] = web3.PublicKey.findProgramAddressSync( + [Buffer.from("GLOBAL")], + balancePayment.programId + ); + const globalAccount = await balancePayment.account.globalAccount.fetch( + globalAccountPubkey + ); + + const tx = balancePayment.methods + .lock(recoverInfo, amount) + .accountsPartial({ + user, + bot: globalAccount.bot, + }); + await execute(tx); + }); + +cli + .command("settle") + .requiredOption("--user ", "User Pubkey") + .requiredOption("--nonce ", "Nonce") + .requiredOption("--amountToTransfer ", "Amount in SOL") + .action(async (opt) => { + const balancePayment = getBalancePaymentProgram(); + const user = new web3.PublicKey(opt.user); + const nonce = new BN(opt.nonce); + const amountToTransfer = sol(opt.amountToTransfer); + const [globalAccountPubkey, _] = web3.PublicKey.findProgramAddressSync( + [Buffer.from("GLOBAL")], + balancePayment.programId + ); + const globalAccount = await balancePayment.account.globalAccount.fetch( + globalAccountPubkey + ); + const tx = balancePayment.methods + .settle(nonce, amountToTransfer) + .accountsPartial({ + user, + treasury: globalAccount.treasury, + bot: globalAccount.bot, + }); + await execute(tx); + }); + + cli + .command("pay") + .requiredOption("--user ", "User Pubkey") + .requiredOption("--amountToTransfer ", "Amount in SOL") + .requiredOption("--recoverInfo ", "Recover Info (Base64)") + .action(async (opt) => { + const balancePayment = getBalancePaymentProgram(); + const user = new web3.PublicKey(opt.user); + const amountToTransfer = sol(opt.amountToTransfer); + const recoverInfo = JSON.parse( + Buffer.from(opt.recoverInfo, "base64").toString() + ); + + recoverInfo.signature = Array.from(recoverInfo.signature); + recoverInfo.payload = Array.from(recoverInfo.payload); + recoverInfo.deadline = new BN(recoverInfo.deadline, "hex"); + + const [globalAccountPubkey, _] = web3.PublicKey.findProgramAddressSync( + [Buffer.from("GLOBAL")], + balancePayment.programId + ); + const globalAccount = await balancePayment.account.globalAccount.fetch( + globalAccountPubkey + ); + + const tx = balancePayment.methods + .pay(recoverInfo, amountToTransfer) + .accountsPartial({ + user, + treasury: globalAccount.treasury, + bot: globalAccount.bot, + }); + await execute(tx); + }); + +cli.command("show_global").action(async () => { + const balancePayment = getBalancePaymentProgram(); + const [globalAccountPubkey, _] = web3.PublicKey.findProgramAddressSync( + [Buffer.from("GLOBAL")], + balancePayment.programId + ); + const globalAccount = await balancePayment.account.globalAccount.fetch( + globalAccountPubkey + ); + showObj(globalAccount); +}); + +cli.command("show_users").action(async () => { + const balancePayment = getBalancePaymentProgram(); + const allUsers = await balancePayment.account.userAccount.all(); + + allUsers.forEach((user) => { + showObj(user); + console.log("-".repeat(50)); + }); +}); + +cli.parse(); diff --git a/dephy-vending_machine-examples/balance-payment/tests/balance-payment.ts b/dephy-vending_machine-examples/balance-payment/tests/balance-payment.ts new file mode 100644 index 0000000..8d9b009 --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/tests/balance-payment.ts @@ -0,0 +1,341 @@ +import * as anchor from "@coral-xyz/anchor"; +import { BN, Program, web3 } from "@coral-xyz/anchor"; +import { v4 as uuidv4 } from "uuid"; +import { BalancePayment } from "../target/types/balance_payment"; +import { assert } from "chai"; +import keccak from "keccak"; +import * as ed from "@noble/ed25519"; +import bs58 from 'bs58'; + +const SIGN_MESSAGE_PREFIX = "DePHY vending machine/Example:\n"; + +const sol = function (n: number) { + return new BN(n * web3.LAMPORTS_PER_SOL); +}; + +describe("balance-payment", () => { + anchor.setProvider(anchor.AnchorProvider.env()); + + const program = anchor.workspace.BalancePayment as Program; + + const authority = web3.Keypair.generate(); + const treasury = web3.Keypair.generate(); + const bot = web3.Keypair.generate(); + + const user = web3.Keypair.generate(); + + const [globalAccountPubkey, _] = web3.PublicKey.findProgramAddressSync( + [Buffer.from("GLOBAL")], + anchor.workspace.BalancePayment.programId + ); + + const getUserAccountPubkey = (user: web3.PublicKey) => { + const [userAccountPubkey, _] = web3.PublicKey.findProgramAddressSync( + [Buffer.from("USER"), user.toBuffer()], + anchor.workspace.BalancePayment.programId + ); + return userAccountPubkey; + }; + + const getUserVaultPubkey = (user: web3.PublicKey) => { + const [vaultPubkey, _] = web3.PublicKey.findProgramAddressSync( + [Buffer.from("VAULT"), user.toBuffer()], + anchor.workspace.BalancePayment.programId + ); + return vaultPubkey; + }; + + const getLockAccountPubkey = (user: web3.PublicKey, nonce: BN) => { + const [lockAccountPubkey, _] = web3.PublicKey.findProgramAddressSync( + [ + Buffer.from("LOCK"), + user.toBuffer(), + nonce.toArrayLike(Buffer, "le", 8), + ], + program.programId + ); + return lockAccountPubkey; + }; + + const generate64ByteUUIDPayload = (): Buffer => { + const uuid = uuidv4().replace(/-/g, ""); // 去掉连字符 + const uuidBuffer = Buffer.from(uuid, "hex"); + + const extendedBuffer = Buffer.concat([uuidBuffer, Buffer.alloc(48, 0)]); + + return extendedBuffer; + }; + const airdrop = async (to: web3.PublicKey, amount: BN) => { + await anchor.Native.system() + .methods.transfer(amount) + .accounts({ to }) + .rpc(); + }; + + before(async () => { + await airdrop(user.publicKey, sol(100)); + }); + + it("initialize", async () => { + const tempTreasury = web3.Keypair.generate().publicKey; + const tempBot = web3.Keypair.generate().publicKey; + const { signature } = await program.methods + .initialize() + .accountsPartial({ + authority: authority.publicKey, + treasury: tempTreasury, + bot: tempBot, + }) + .rpcAndKeys(); + console.log("initialize:", signature); + + const global = await program.account.globalAccount.fetch( + globalAccountPubkey + ); + assert.equal(global.authority.toString(), authority.publicKey.toString()); + assert.equal(global.treasury.toString(), tempTreasury.toString()); + assert.equal(global.bot.toString(), tempBot.toString()); + }); + + it("set treasury", async () => { + const { signature } = await program.methods + .setTreasury() + .accountsPartial({ + authority: authority.publicKey, + treasury: treasury.publicKey, + }) + .signers([authority]) + .rpcAndKeys(); + console.log("set_treasury:", signature); + + const global = await program.account.globalAccount.fetch( + globalAccountPubkey + ); + assert.equal(global.treasury.toString(), treasury.publicKey.toString()); + }); + + it("set bot", async () => { + const { signature } = await program.methods + .setBot() + .accountsPartial({ + authority: authority.publicKey, + bot: bot.publicKey, + }) + .signers([authority]) + .rpcAndKeys(); + console.log("set_bot:", signature); + + const global = await program.account.globalAccount.fetch( + globalAccountPubkey + ); + assert.equal(global.bot.toString(), bot.publicKey.toString()); + }); + + it("register", async () => { + const { signature } = await program.methods + .register() + .accountsPartial({ + user: user.publicKey, + }) + .signers([user]) + .rpcAndKeys(); + console.log("register:", signature); + + const userAccountPubkey = getUserAccountPubkey(user.publicKey); + const userAccount = await program.account.userAccount.fetch( + userAccountPubkey + ); + assert.equal( + userAccount.vault.toString(), + getUserVaultPubkey(user.publicKey).toString() + ); + }); + + it("deposit", async () => { + const amount = sol(11); + + const { signature } = await program.methods + .deposit(amount) + .accountsPartial({ + user: user.publicKey, + }) + .signers([user]) + .rpcAndKeys(); + console.log("deposit:", signature); + + const userVaultPubkey = getUserVaultPubkey(user.publicKey); + const userVaultBalance = await program.provider.connection.getBalance( + userVaultPubkey + ); + + assert(amount.eq(new BN(userVaultBalance))); + }); + + it("withdraw", async () => { + const amount = sol(1); + + const { signature } = await program.methods + .withdraw(amount) + .accountsPartial({ + user: user.publicKey, + }) + .signers([user]) + .rpcAndKeys(); + console.log("withdraw:", signature); + + const userVaultPubkey = getUserVaultPubkey(user.publicKey); + const userVaultBalance = await program.provider.connection.getBalance( + userVaultPubkey + ); + + assert(sol(10).eq(new BN(userVaultBalance))); + }); + + it("lock", async () => { + const amount = sol(10); + + const userAccountPubkey = getUserAccountPubkey(user.publicKey); + + let userAccount = await program.account.userAccount.fetch( + userAccountPubkey + ); + + const nonce = userAccount.nonce; + const payload = generate64ByteUUIDPayload(); + + const deadline = new BN(Date.now() / 1000 + 60 * 30); // 30 minutes later + const message = Buffer.concat([ + payload, + nonce.toArrayLike(Buffer, "le", 8), + deadline.toArrayLike(Buffer, "le", 8), + ]); + + const messageHash = keccak("keccak256").update(message).digest(); + const hashedMessageBase58 = bs58.encode(messageHash); + const digest = new TextEncoder().encode(`${SIGN_MESSAGE_PREFIX}${hashedMessageBase58}`); + + const privateKey = user.secretKey.slice(0, 32); + + const signature = await ed.signAsync(digest, privateKey); + + const recoverInfo = { + signature: Array.from(signature), + payload: Array.from(payload), + deadline, + }; + + const { signature: txSignature } = await program.methods + .lock(recoverInfo, amount) + .accountsPartial({ + user: user.publicKey, + bot: bot.publicKey, + }) + .signers([bot]) + .rpcAndKeys(); + + console.log("lock:", txSignature); + + const lockAccountPubkey = getLockAccountPubkey(user.publicKey, nonce); + const lockAccount = await program.account.lockAccount.fetch( + lockAccountPubkey + ); + assert.equal(lockAccount.amount.toString(), amount.toString()); + + userAccount = await program.account.userAccount.fetch(userAccountPubkey); + assert(userAccount.lockedAmount.eq(amount)); + }); + + it("settle", async () => { + const nonce = new BN(0); + const amountToTransfer = sol(5); + + const { signature } = await program.methods + .settle(nonce, amountToTransfer) + .accountsPartial({ + user: user.publicKey, + treasury: treasury.publicKey, + bot: bot.publicKey, + }) + .signers([bot]) + .rpcAndKeys(); + + console.log("settle:", signature); + + const treasuryBalance = await program.provider.connection.getBalance( + treasury.publicKey + ); + assert.equal(treasuryBalance, amountToTransfer.toNumber()); + + const lockAccountPubkey = getLockAccountPubkey(user.publicKey, nonce); + + try { + await program.account.lockAccount.fetch( + lockAccountPubkey + ); + } catch (error) { + assert(error.message.includes("Account does not exist")) + } + + const userAccountPubkey = getUserAccountPubkey(user.publicKey); + const userAccount = await program.account.userAccount.fetch( + userAccountPubkey + ); + assert(userAccount.lockedAmount.eq(new BN(0))); + }); + + it("pay", async () => { + const amountToTransfer = sol(1); + + const userAccountPubkey = getUserAccountPubkey(user.publicKey); + + let userAccount = await program.account.userAccount.fetch( + userAccountPubkey + ); + + const nonce = userAccount.nonce; + const payload = generate64ByteUUIDPayload(); + + const deadline = new BN(Date.now() / 1000 + 60 * 30); // 30 minutes later + const message = Buffer.concat([ + payload, + nonce.toArrayLike(Buffer, "le", 8), + deadline.toArrayLike(Buffer, "le", 8), + ]); + + const messageHash = keccak("keccak256").update(message).digest(); + const hashedMessageBase58 = bs58.encode(messageHash); + const digest = new TextEncoder().encode(`${SIGN_MESSAGE_PREFIX}${hashedMessageBase58}`); + + const privateKey = user.secretKey.slice(0, 32); + + const signature = await ed.signAsync(digest, privateKey); + + const recoverInfo = { + signature: Array.from(signature), + payload: Array.from(payload), + deadline, + }; + + const vaultBalanceBefore = await program.provider.connection.getBalance( + userAccount.vault + ); + + const { signature: txSignature } = await program.methods + .pay(recoverInfo, amountToTransfer) + .accountsPartial({ + user: user.publicKey, + treasury: treasury.publicKey, + bot: bot.publicKey, + }) + .signers([bot]) + .rpcAndKeys(); + + console.log("pay:", txSignature); + + const vaultBalanceAfter = await program.provider.connection.getBalance( + userAccount.vault + ); + + assert.equal(vaultBalanceBefore - vaultBalanceAfter, amountToTransfer.toNumber()); + }); +}); diff --git a/dephy-vending_machine-examples/balance-payment/tsconfig.json b/dephy-vending_machine-examples/balance-payment/tsconfig.json new file mode 100644 index 0000000..247d160 --- /dev/null +++ b/dephy-vending_machine-examples/balance-payment/tsconfig.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "types": ["mocha", "chai"], + "typeRoots": ["./node_modules/@types"], + "lib": ["es2015"], + "module": "commonjs", + "target": "es6", + "esModuleInterop": true, + "resolveJsonModule": true + } +} diff --git a/dephy-vending_machine-examples/cliff.toml b/dephy-vending_machine-examples/cliff.toml new file mode 100644 index 0000000..cfd438c --- /dev/null +++ b/dephy-vending_machine-examples/cliff.toml @@ -0,0 +1,95 @@ +# git-cliff ~ configuration file +# https://git-cliff.org/docs/configuration + +[changelog] +# changelog header +header = """ +# Changelog\n +All notable changes to this project will be documented in this file. See [conventional commits](https://www.conventionalcommits.org/) for commit guidelines.\n +""" +# template for the changelog body +# https://keats.github.io/tera/docs/#introduction +body = """ +--- +{% if version %}\ + {% if previous.version %}\ + ## [{{ version | trim_start_matches(pat="v") }}]($REPO/compare/{{ previous.version }}..{{ version }}) - {{ timestamp | date(format="%Y-%m-%d") }} + {% else %}\ + ## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }} + {% endif %}\ +{% else %}\ + ## [unreleased] +{% endif %}\ +{% for group, commits in commits | group_by(attribute="group") %} + ### {{ group | striptags | trim | upper_first }} + {% for commit in commits + | filter(attribute="scope") + | sort(attribute="scope") %} + - **({{commit.scope}})**{% if commit.breaking %} [**breaking**]{% endif %} \ + {{ commit.message|trim }} - ([{{ commit.id | truncate(length=7, end="") }}]($REPO/commit/{{ commit.id }})) - {{ commit.author.name }} + {%- endfor -%} + {% raw %}\n{% endraw %}\ + {%- for commit in commits %} + {%- if commit.scope -%} + {% else -%} + - {% if commit.breaking %} [**breaking**]{% endif %}\ + {{ commit.message|trim }} - ([{{ commit.id | truncate(length=7, end="") }}]($REPO/commit/{{ commit.id }})) - {{ commit.author.name }} + {% endif -%} + {% endfor -%} +{% endfor %}\n +""" +# template for the changelog footer +footer = """ + +""" +# remove the leading and trailing whitespace from the templates +trim = true +# postprocessors +postprocessors = [ + { pattern = '\$REPO', replace = "https://github.com/dephy-io/dephy-vending_machine-examples" }, # replace repository URL +] + +[git] +# parse the commits based on https://www.conventionalcommits.org +conventional_commits = true +# filter out the commits that are not conventional +filter_unconventional = false +# process each line of a commit as an individual commit +split_commits = false +# regex for preprocessing the commit messages +commit_preprocessors = [ + # { pattern = '\((\w+\s)?#([0-9]+)\)', replace = "([#${2}](https://github.com/orhun/git-cliff/issues/${2}))"}, # replace issue numbers +] +# regex for parsing and grouping commits +commit_parsers = [ + { message = "\\[skip", skip = true }, + { message = "\\p{Han}", skip = true }, + { message = "^feat", group = "Features" }, + { message = "^fix", group = "Bug Fixes" }, + { message = "^doc", group = "Documentation" }, + { message = "^perf", group = "Performance" }, + { message = "^refactor", group = "Refactoring" }, + { message = "^style", group = "Style" }, + { message = "^revert", group = "Revert" }, + { message = "^test", group = "Tests" }, + { message = "^chore\\(version\\):", skip = true }, + { message = "^chore", group = "Miscellaneous Chores" }, + { message = ".*", group = "Other" }, + { body = ".*security", group = "Security" }, +] +# protect breaking changes from being skipped due to matching a skipping commit_parser +protect_breaking_commits = false +# filter out the commits that are not matched by commit parsers +filter_commits = false +# regex for matching git tags +tag_pattern = "v[0-9].*" +# regex for skipping tags +skip_tags = "v0.1.0-beta.1" +# regex for ignoring tags +ignore_tags = "" +# sort the tags topologically +topo_order = false +# sort the commits inside sections by oldest/newest order +sort_commits = "oldest" +# limit the number of commits included in the changelog. +# limit_commits = 42 diff --git a/dephy-vending_machine-examples/deny.toml b/dephy-vending_machine-examples/deny.toml new file mode 100644 index 0000000..36e879a --- /dev/null +++ b/dephy-vending_machine-examples/deny.toml @@ -0,0 +1,58 @@ +[advisories] +version = 2 +yanked = "warn" +db-path = "~/.cargo/advisory-db" +db-urls = ["https://github.com/rustsec/advisory-db"] +ignore = [ + # waiting for nostr crates to be updated + "RUSTSEC-2024-0384", + # waiting for solana crates to be updated + "RUSTSEC-2022-0093", + # waiting for solana crates to be updated + "RUSTSEC-2024-0388", + # waiting for solana crates to be updated + "RUSTSEC-2024-0344", + # waiting for solana crates to be updated + "RUSTSEC-2021-0145", + # waiting for solana crates to be updated + "RUSTSEC-2024-0375", +] + +[bans] +multiple-versions = "warn" +wildcards = "deny" +highlight = "all" + +[licenses] +version = 2 +confidence-threshold = 0.8 + +allow = [ + "MIT", + "MITNFA", + "Apache-2.0", + "Apache-2.0 WITH LLVM-exception", + "BSD-3-Clause", + "BSD-2-Clause", + "0BSD", + "ISC", + "Unicode-3.0", + "Unicode-DFS-2016", + "Unlicense", + "MPL-2.0", + "CC0-1.0", + "Zlib", + # https://github.com/briansmith/ring/issues/902 + "LicenseRef-ring", +] + +[[licenses.clarify]] +name = "ring" +expression = "LicenseRef-ring" +license-files = [{ path = "LICENSE", hash = 0xbd0eed23 }] + +[sources] +unknown-registry = "deny" +unknown-git = "deny" +allow-registry = ["https://github.com/rust-lang/crates.io-index"] +allow-git = ["git://github.com/anza-xyz/agave.git"] diff --git a/dephy-vending_machine-examples/doc/architecture.png b/dephy-vending_machine-examples/doc/architecture.png new file mode 100644 index 0000000000000000000000000000000000000000..f102438f92a263c84b087ece2a196caeff991b9a GIT binary patch literal 274452 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 z

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 + --nostr-relay 'ws://dephy-messaging-network:8000' + --key '80ed9975bc5c18c8852c202e4ddc0ae62abf7d9484c3a0d425f501623907129b' + --solana-rpc-url "${SOLANA_RPC_URL:-http://host.docker.internal:8899}" + --pg-url 'postgresql://dephy:dephy@postgres:5432/dephy_decharge_controller_server' + + dephy-decharge-controller-node-1: + depends_on: + - dephy-messaging-network + image: dephyio/dephy-vending-machine-examples:main + restart: always + entrypoint: /usr/bin/dephy-decharge-controller-node + user: root # have to be root to write key file to data directory + environment: + RUST_LOG: "debug" + RUST_BACKTRACE: "1" + volumes: + - dephy_decharge_controller_node_1_data:/opt/dephy-vending-machine-examples/data:rw + command: > + --nostr-relay 'ws://dephy-messaging-network:8000' + --solana-rpc-url "${SOLANA_RPC_URL:-http://host.docker.internal:8899}" + --machine-pubkeys 'd041ea9854f2117b82452457c4e6d6593a96524027cd4032d2f40046deb78d93' + --admin-pubkey '90b6bb6472b2609c63dfb588aa1a10780dc043ffc0ab2349679c50644c0bc445' + + dephy-gacha-controller: + depends_on: + - dephy-messaging-network + image: dephyio/dephy-vending-machine-examples:main + restart: always + entrypoint: /usr/bin/dephy-gacha-controller + user: root # have to be root to write key file to data directory + environment: + RUST_LOG: "debug" + RUST_BACKTRACE: "1" + volumes: + - dephy_gacha_controller_data:/opt/dephy-vending-machine-examples/data:rw + - ./keypairs/bot.demo.json:/opt/dephy-vending-machine-examples/data/solana-keypair + command: > + --nostr-relay 'ws://dephy-messaging-network:8000' + --solana-rpc-url "${SOLANA_RPC_URL:-http://host.docker.internal:8899}" + --machine-pubkeys 'd041ea9854f2117b82452457c4e6d6593a96524027cd4032d2f40046deb78d93' + --admin-pubkey 'd041ea9854f2117b82452457c4e6d6593a96524027cd4032d2f40046deb78d93' + +volumes: + postgres_data: + dephy_decharge_controller_node_1_data: + dephy_gacha_controller_data: diff --git a/dephy-vending_machine-examples/examples/decharge-controller/Cargo.toml b/dephy-vending_machine-examples/examples/decharge-controller/Cargo.toml new file mode 100644 index 0000000..7e0bbab --- /dev/null +++ b/dephy-vending_machine-examples/examples/decharge-controller/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "dephy-decharge-controller" +version = "0.1.0" +edition = "2021" +license.workspace = true + +[dependencies] +clap = { workspace = true } +dephy-balance-payment-sdk = { workspace = true } +futures = { workspace = true } +nostr = { workspace = true } +nostr-sdk = { workspace = true } +sea-query = "0.32.1" +sea-query-binder = { version = "0.7.0", features = ["runtime-tokio", "sqlx-postgres"] } +serde = { workspace = true } +serde_json = { workspace = true } +sqlx = { version = "0.8.3", features = ["postgres", "runtime-tokio"] } +thiserror = { workspace = true } +tokio = { workspace = true, features = ["process", "rt-multi-thread"] } +tracing = { workspace = true } +tracing-subscriber = { workspace = true, features = ["env-filter"] } + +[[bin]] +name = "dephy-decharge-controller-node" +path = "bin/dephy-decharge-controller-node.rs" + +[[bin]] +name = "dephy-decharge-controller-server" +path = "bin/dephy-decharge-controller-server.rs" diff --git a/dephy-vending_machine-examples/examples/decharge-controller/README.md b/dephy-vending_machine-examples/examples/decharge-controller/README.md new file mode 100644 index 0000000..a153c50 --- /dev/null +++ b/dephy-vending_machine-examples/examples/decharge-controller/README.md @@ -0,0 +1,84 @@ +# dephy-decharge-controller + +## Run by Docker Compose + +```bash +docker compose up +``` + +## Run manually + +### Prepare + +In this example, you should have a messaging network running on `ws://127.0.0.1:8000`. +You can modify `--nostr-relay` if it is running on a different address. + +To run a messaging network you need a postgresql database with schema: + +```sql +CREATE TABLE IF NOT EXISTS events ( + id bigserial PRIMARY KEY, + event_id character varying NOT NULL, + prev_event_id character varying NOT NULL, + pubkey character varying NOT NULL, + created_at bigint NOT NULL, + original character varying NOT NULL, + "session" character varying NOT NULL, + mention character varying, + + CONSTRAINT events_unique_event_id + UNIQUE (event_id), + + CONSTRAINT events_unique_pubkey_session_prev_event_id + UNIQUE (pubkey, session, prev_event_id) +); +``` + +To run a messaging network by docker: + +```shell +docker run --name dephy-messaging-network --restart=always --network="host" -d dephyio/dephy-messaging-network:master serve --pg-url 'postgresql://:@

/' +``` + +### Run Server + +The schema of the database is in [migrations](./migrations/). + +You can migrate it by [sqlx-cli](https://crates.io/crates/sqlx-cli) or enable those sql manually. To migrate it by sqlx-cli: + +```shell +sqlx database create --database-url postgresql://>@
/ +sqlx migrate run --database-url postgresql://:@
/ +``` + +The server need your solana keypair. + +```shell +mkdir data +# copy your keypair to data/solana-keypair +``` + +To run the server: + +```shell +cargo run --bin dephy-decharge-controller-server -- --nostr-relay ws://127.0.0.1:8000 --key --pg-url postgresql://:@
/ +``` + +### Run Node (this is on charger equipment side) + +The node need your solana keypair. + +```shell +mkdir data +# copy your keypair to data/solana-keypair +``` + +```shell +cargo run --bin dephy-decharge-controller-node -- --nostr-relay ws://127.0.0.1:8000 --machine-pubkeys d041ea9854f2117b82452457c4e6d6593a96524027cd4032d2f40046deb78d93 --admin-pubkey +``` + +### Cli Example (it simulates a charging process) + +```shell +cargo run --example cli -- --nostr-relay ws://127.0.0.1:8000 --machine-pubkey d041ea9854f2117b82452457c4e6d6593a96524027cd4032d2f40046deb78d93 --user --nonce --recover-info +``` diff --git a/dephy-vending_machine-examples/examples/decharge-controller/bin/dephy-decharge-controller-node.rs b/dephy-vending_machine-examples/examples/decharge-controller/bin/dephy-decharge-controller-node.rs new file mode 100644 index 0000000..9152019 --- /dev/null +++ b/dephy-vending_machine-examples/examples/decharge-controller/bin/dephy-decharge-controller-node.rs @@ -0,0 +1,128 @@ +use std::path::PathBuf; + +use clap::value_parser; +use clap::Arg; +use clap::ArgAction; +use clap::ArgMatches; +use clap::Command; +use nostr::Keys; + +const SESSION: &str = "dephy-decharge-controller"; + +fn parse_args() -> Command { + Command::new("dephy-decharge-controller-node") + .arg_required_else_help(true) + .about("Dephy decharge controller node daemon") + .version(dephy_decharge_controller::VERSION) + .arg( + Arg::new("NOSTR_RELAY") + .long("nostr-relay") + .num_args(1) + .required(true) + .action(ArgAction::Set) + .help("Nostr relay address"), + ) + .arg( + Arg::new("KEY_FILE") + .long("key-file") + .num_args(1) + .default_value("data/key") + .value_parser(value_parser!(PathBuf)) + .action(ArgAction::Set) + .help("Path to the file containing the hex or bech32 secret key"), + ) + .arg( + Arg::new("ADMIN_PUBKEY") + .long("admin-pubkey") + .num_args(1) + .required(true) + .action(ArgAction::Set) + .help("Admin public key"), + ) + .arg( + Arg::new("MACHINE_PUBKEYS") + .long("machine-pubkeys") + .num_args(1) + .required(true) + .action(ArgAction::Set) + .help("Machine public keys, comma separated"), + ) + .arg( + Arg::new("SOLANA_RPC_URL") + .long("solana-rpc-url") + .num_args(1) + .required(true) + .action(ArgAction::Set) + .help("Solana RPC URL"), + ) +} + +async fn controller(args: &ArgMatches) { + let nostr_relay = args.get_one::("NOSTR_RELAY").unwrap(); + let key_file_path = args.get_one::("KEY_FILE").unwrap(); + let keys = read_or_generate_keypair(key_file_path); + let admin_pubkey = args + .get_one::("ADMIN_PUBKEY") + .unwrap() + .parse() + .expect("Invalid admin pubkey"); + let machine_pubkeys = args + .get_one::("MACHINE_PUBKEYS") + .unwrap() + .split(',') + .map(|s| s.parse().expect("Invalid machine pubkey")) + .collect(); + let solana_rpc_url = args.get_one::("SOLANA_RPC_URL").unwrap(); + + println!("nostr relay: {}", nostr_relay); + println!("pubkey: {}", keys.public_key()); + + let client = dephy_decharge_controller::RelayClient::new(nostr_relay, &keys, SESSION, 4096) + .await + .expect("Failed to connect to relay"); + + let message_handler = dephy_decharge_controller::node::MessageHandler::new( + client, + keys.public_key(), + admin_pubkey, + machine_pubkeys, + solana_rpc_url, + ); + + message_handler.run().await +} + +fn read_or_generate_keypair(path: &PathBuf) -> Keys { + let keys = std::fs::read_to_string(path) + .map(|content| content.trim().parse().expect("Invalid key")) + .unwrap_or_else(|_| { + tracing::info!( + "Key file not found, generating a new one at: {}", + path.display() + ); + let keys = Keys::generate(); + std::fs::write(path, keys.secret_key().to_secret_hex()) + .unwrap_or_else(|e| panic!("Failed to write key {}: {e:?}", path.display())); + keys + }); + + let pubkey_path = path.with_extension("pub"); + std::fs::write(&pubkey_path, keys.public_key().to_hex()).unwrap_or_else(|e| { + panic!( + "Failed to write public key {}: {e:?}", + pubkey_path.display() + ) + }); + + keys +} + +#[tokio::main] +async fn main() { + let _ = tracing_subscriber::fmt() + .with_env_filter(tracing_subscriber::EnvFilter::from_default_env()) + .try_init(); + + let cmd = parse_args(); + controller(&cmd.get_matches()).await; +} diff --git a/dephy-vending_machine-examples/examples/decharge-controller/bin/dephy-decharge-controller-server.rs b/dephy-vending_machine-examples/examples/decharge-controller/bin/dephy-decharge-controller-server.rs new file mode 100644 index 0000000..6f82760 --- /dev/null +++ b/dephy-vending_machine-examples/examples/decharge-controller/bin/dephy-decharge-controller-server.rs @@ -0,0 +1,110 @@ +use std::path::PathBuf; + +use clap::value_parser; +use clap::Arg; +use clap::ArgAction; +use clap::ArgMatches; +use clap::Command; +use nostr::Keys; + +const SESSION: &str = "dephy-decharge-controller"; + +fn parse_args() -> Command { + Command::new("dephy-decharge-controller-server") + .arg_required_else_help(true) + .about("Dephy decharge controller server") + .version(dephy_decharge_controller::VERSION) + .arg( + Arg::new("NOSTR_RELAY") + .long("nostr-relay") + .num_args(1) + .required(true) + .action(ArgAction::Set) + .help("Nostr relay address"), + ) + .arg( + Arg::new("KEY") + .long("key") + .num_args(1) + .required(true) + .action(ArgAction::Set) + .help("Hex or bech32 secret key"), + ) + .arg( + Arg::new("PG_URL") + .long("pg-url") + .num_args(1) + .required(true) + .action(ArgAction::Set) + .help("Will use this address to connect to postgres"), + ) + .arg( + Arg::new("SOLANA_RPC_URL") + .long("solana-rpc-url") + .num_args(1) + .required(true) + .action(ArgAction::Set) + .help("Solana RPC URL"), + ) + .arg( + Arg::new("SOLANA_KEYPAIR") + .long("solana-keypair") + .num_args(1) + .default_value("data/solana-keypair") + .value_parser(value_parser!(PathBuf)) + .action(ArgAction::Set) + .help("Solana keypair path"), + ) +} + +async fn controller(args: &ArgMatches) { + let nostr_relay = args.get_one::("NOSTR_RELAY").unwrap(); + let keys: Keys = args + .get_one::("KEY") + .unwrap() + .parse() + .expect("Invalid key"); + let pg_url = args.get_one::("PG_URL").unwrap(); + let solana_rpc_url = args.get_one::("SOLANA_RPC_URL").unwrap(); + let solana_keypair_path = args.get_one::("SOLANA_KEYPAIR").unwrap(); + if !solana_keypair_path.exists() { + panic!( + "Solana keypair file not found: {}", + solana_keypair_path.display() + ); + } + + println!("nostr relay: {}", nostr_relay); + println!("pubkey: {}", keys.public_key()); + + let client = dephy_decharge_controller::RelayClient::new(nostr_relay, &keys, SESSION, 4096) + .await + .expect("Failed to connect to relay"); + + let db = sqlx::PgPool::connect(pg_url) + .await + .expect("Failed to connect to database"); + let state = dephy_decharge_controller::server::State::new(db); + + let message_handler = dephy_decharge_controller::server::MessageHandler::new( + client, + state, + solana_rpc_url, + solana_keypair_path + .to_str() + .expect("Invalid solana keypair path"), + None, + ); + + message_handler.run().await +} + +#[tokio::main] +async fn main() { + let _ = tracing_subscriber::fmt() + .with_env_filter(tracing_subscriber::EnvFilter::from_default_env()) + .try_init(); + + let cmd = parse_args(); + controller(&cmd.get_matches()).await; +} diff --git a/dephy-vending_machine-examples/examples/decharge-controller/examples/cli.rs b/dephy-vending_machine-examples/examples/decharge-controller/examples/cli.rs new file mode 100644 index 0000000..a251027 --- /dev/null +++ b/dephy-vending_machine-examples/examples/decharge-controller/examples/cli.rs @@ -0,0 +1,158 @@ +use std::path::PathBuf; + +use clap::value_parser; +use clap::Arg; +use clap::ArgAction; +use clap::ArgMatches; +use clap::Command; +use dephy_decharge_controller::message::DephyDechargeMessage; +use dephy_decharge_controller::message::DephyDechargeMessageRequestPayload; +use dephy_decharge_controller::message::DephyDechargeStatus; +use dephy_decharge_controller::message::DephyDechargeStatusReason; +use nostr::Keys; +use nostr::Timestamp; +use nostr_sdk::EventId; + +const SESSION: &str = "dephy-decharge-controller"; + +fn parse_args() -> Command { + Command::new("dephy-decharge-controller-cli") + .arg_required_else_help(true) + .about("Dephy decharge controller") + .version(dephy_decharge_controller::VERSION) + .arg( + Arg::new("NOSTR_RELAY") + .long("nostr-relay") + .num_args(1) + .required(true) + .action(ArgAction::Set) + .help("Nostr relay address"), + ) + .arg( + Arg::new("KEY_FILE") + .long("key-file") + .num_args(1) + .default_value("data/key") + .value_parser(value_parser!(PathBuf)) + .action(ArgAction::Set) + .help("Path to the file containing the hex or bech32 secret key"), + ) + .arg( + Arg::new("MACHINE_PUBKEY") + .long("machine-pubkey") + .num_args(1) + .required(true) + .action(ArgAction::Set) + .help("Machine public keys, comma separated"), + ) + .arg( + Arg::new("user") + .long("user") + .num_args(1) + .required(true) + .action(ArgAction::Set) + .help("User public key"), + ) + .arg( + Arg::new("nonce") + .long("nonce") + .num_args(1) + .required(true) + .value_parser(value_parser!(u64)) + .action(ArgAction::Set) + .help("Nonce"), + ) + .arg( + Arg::new("recover_info") + .long("recover-info") + .num_args(1) + .required(true) + .action(ArgAction::Set) + .help("Recover info"), + ) +} + +async fn cli(args: &ArgMatches) { + let nostr_relay = args.get_one::("NOSTR_RELAY").unwrap(); + let key_file_path = args.get_one::("KEY_FILE").unwrap(); + let keys = read_or_generate_keypair(key_file_path); + let machine_pubkey = args + .get_one::("MACHINE_PUBKEY") + .unwrap() + .parse() + .expect("Invalid machine pubkey"); + let user = args.get_one::("user").unwrap(); + let nonce = args.get_one::("nonce").unwrap(); + let recover_info = args.get_one::("recover_info").unwrap(); + + let client = dephy_decharge_controller::RelayClient::new(nostr_relay, &keys, SESSION, 4096) + .await + .expect("Failed to connect to relay"); + + let mut notifications = client.notifications(); + client + .subscribe(Timestamp::now(), [machine_pubkey]) + .await + .expect("Failed to subscribe"); + + let handler = tokio::spawn(async move { + loop { + let notification = notifications.recv().await; + tracing::info!("Received notification: {:?}", notification); + } + }); + + let payload = serde_json::to_string(&DephyDechargeMessageRequestPayload { + user: user.clone(), + nonce: *nonce, + recover_info: recover_info.clone(), + }) + .expect("Failed to serialize payload"); + + client + .send_event(&machine_pubkey.to_hex(), &DephyDechargeMessage::Request { + to_status: DephyDechargeStatus::Working, + reason: DephyDechargeStatusReason::UserRequest, + initial_request: EventId::all_zeros(), + payload, + }) + .await + .expect("Failed to send event"); + + handler.await.expect("Notification handler failed"); +} + +fn read_or_generate_keypair(path: &PathBuf) -> Keys { + let keys = std::fs::read_to_string(path) + .map(|content| content.trim().parse().expect("Invalid key")) + .unwrap_or_else(|_| { + tracing::info!( + "Key file not found, generating a new one at: {}", + path.display() + ); + let keys = Keys::generate(); + std::fs::write(path, keys.secret_key().to_secret_hex()) + .unwrap_or_else(|e| panic!("Failed to write key {}: {e:?}", path.display())); + keys + }); + + let pubkey_path = path.with_extension("pub"); + std::fs::write(&pubkey_path, keys.public_key().to_hex()).unwrap_or_else(|e| { + panic!( + "Failed to write public key {}: {e:?}", + pubkey_path.display() + ) + }); + + keys +} + +#[tokio::main] +async fn main() { + let _ = tracing_subscriber::fmt() + .with_env_filter(tracing_subscriber::EnvFilter::from_default_env()) + .try_init(); + + let cmd = parse_args(); + cli(&cmd.get_matches()).await; +} diff --git a/dephy-vending_machine-examples/examples/decharge-controller/migrations/20250116011256_initial.sql b/dephy-vending_machine-examples/examples/decharge-controller/migrations/20250116011256_initial.sql new file mode 100644 index 0000000..ef2a043 --- /dev/null +++ b/dephy-vending_machine-examples/examples/decharge-controller/migrations/20250116011256_initial.sql @@ -0,0 +1,6 @@ +CREATE TABLE IF NOT EXISTS received_events ( + id bigserial PRIMARY KEY, + event_id character varying NOT NULL, + created_at bigint NOT NULL, + is_processed boolean NOT NULL +); diff --git a/dephy-vending_machine-examples/examples/decharge-controller/src/lib.rs b/dephy-vending_machine-examples/examples/decharge-controller/src/lib.rs new file mode 100644 index 0000000..2da85c3 --- /dev/null +++ b/dephy-vending_machine-examples/examples/decharge-controller/src/lib.rs @@ -0,0 +1,9 @@ +pub mod message; +pub mod node; +mod relay_client; +pub mod server; + +/// dephy-decharge-controller version +pub const VERSION: &str = env!("CARGO_PKG_VERSION"); + +pub use relay_client::RelayClient; diff --git a/dephy-vending_machine-examples/examples/decharge-controller/src/message.rs b/dephy-vending_machine-examples/examples/decharge-controller/src/message.rs new file mode 100644 index 0000000..5548275 --- /dev/null +++ b/dephy-vending_machine-examples/examples/decharge-controller/src/message.rs @@ -0,0 +1,50 @@ +use nostr::EventId; +use serde::Deserialize; +use serde::Serialize; + +#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)] +#[repr(u8)] +pub enum DephyDechargeStatus { + Available = 1, + Working = 2, +} + +#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)] +#[repr(u8)] +pub enum DephyDechargeStatusReason { + UserRequest = 1, + AdminRequest = 2, + UserBehaviour = 3, + LockFailed = 5, + Reset = 4, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum DephyDechargeMessage { + Request { + to_status: DephyDechargeStatus, + reason: DephyDechargeStatusReason, + initial_request: EventId, + payload: String, + }, + Status { + status: DephyDechargeStatus, + reason: DephyDechargeStatusReason, + initial_request: EventId, + payload: String, + }, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct DephyDechargeMessageRequestPayload { + pub user: String, + pub nonce: u64, + pub recover_info: String, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct DephyDechargeMessageStatusPayload { + pub user: String, + pub nonce: u64, + pub recover_info: String, +} diff --git a/dephy-vending_machine-examples/examples/decharge-controller/src/node/message_handler.rs b/dephy-vending_machine-examples/examples/decharge-controller/src/node/message_handler.rs new file mode 100644 index 0000000..db134f6 --- /dev/null +++ b/dephy-vending_machine-examples/examples/decharge-controller/src/node/message_handler.rs @@ -0,0 +1,390 @@ +use std::collections::HashMap; +use std::collections::HashSet; + +use nostr::Event; +use nostr::EventId; +use nostr::PublicKey; +use nostr::RelayMessage; +use nostr::Timestamp; +use nostr_sdk::RelayPoolNotification; + +use crate::message::DephyDechargeMessage; +use crate::message::DephyDechargeMessageRequestPayload; +use crate::message::DephyDechargeMessageStatusPayload; +use crate::message::DephyDechargeStatus; +use crate::message::DephyDechargeStatusReason; +use crate::relay_client::extract_mention; +use crate::RelayClient; + +const PREPAID_AMOUNT: u64 = 10_000_000; + +#[derive(Debug, thiserror::Error)] +#[non_exhaustive] +pub enum Error { + #[error("Serde json error: {0}")] + SerdeJson(#[from] serde_json::Error), + #[error("Nostr key error: {0}")] + NostrKey(#[from] nostr::key::Error), + #[error("Relay client error: {0}")] + RelayClient(#[from] crate::relay_client::Error), + #[error("Machine not mentioned in event: {0:?}")] + MachineNotMentioned(Event), + #[error("The machine mentioned by event is not controlled by us: {0:?}")] + MachineNotControlled(Event), + #[error("Only support status event when update machine, but got: {0:?}")] + OnlySupportStatusEventWhenUpdateMachine(Event), +} + +pub struct Machine { + #[allow(dead_code)] + pubkey: PublicKey, + status: DephyDechargeStatus, + initial_request: Option, +} + +pub struct MessageHandler { + client: RelayClient, + controller_pubkey: PublicKey, + admin_pubkey: PublicKey, + machines: HashMap, + started_at: Timestamp, + solana_rpc_url: String, +} + +impl MessageHandler { + pub fn new( + client: RelayClient, + controller_pubkey: PublicKey, + admin_pubkey: PublicKey, + machine_pubkeys: HashSet, + solana_rpc_url: &str, + ) -> Self { + let started_at = Timestamp::now(); + let machines = machine_pubkeys + .into_iter() + .map(|pubkey| { + (pubkey, Machine { + pubkey, + status: DephyDechargeStatus::Available, + initial_request: None, + }) + }) + .collect(); + + Self { + client, + controller_pubkey, + admin_pubkey, + machines, + started_at, + solana_rpc_url: solana_rpc_url.to_string(), + } + } + + pub async fn update_machine(&mut self, event: &Event) -> Result<(), Error> { + let mention = PublicKey::parse( + extract_mention(event).ok_or_else(|| Error::MachineNotMentioned(event.clone()))?, + )?; + + let machine = self + .machines + .get_mut(&mention) + .ok_or_else(|| Error::MachineNotControlled(event.clone()))?; + + let message = serde_json::from_str::(&event.content)?; + + match message { + DephyDechargeMessage::Request { .. } => { + return Err(Error::OnlySupportStatusEventWhenUpdateMachine( + event.clone(), + )) + } + + DephyDechargeMessage::Status { + status, + initial_request, + .. + } => { + machine.status = status; + machine.initial_request = Some(initial_request); + } + } + + Ok(()) + } + + pub async fn run(mut self) { + let mut notifications = self.client.notifications(); + + let checking_client = self.client.clone(); + let relay_checker = async move { + checking_client + .run_relay_checker(std::time::Duration::from_secs(10)) + .await + }; + + let message_handler = async move { + let mut sub_ids = HashMap::new(); + + for machine_pubkey in self.machines.keys().copied() { + let sub_id = self + .client + .subscribe_last_event( + self.started_at, + Some(&self.controller_pubkey), + &machine_pubkey, + ) + .await + .expect("Failed to subscribe events"); + + sub_ids.insert(sub_id, machine_pubkey); + } + + while !sub_ids.is_empty() { + let notification = notifications + .recv() + .await + .expect("Failed to receive notification"); + tracing::debug!("Received notification: {:?}", notification); + + match notification { + RelayPoolNotification::Shutdown => panic!("Relay pool shutdown"), + + RelayPoolNotification::Message { + message: + RelayMessage::Closed { + message, + subscription_id, + }, + .. + } => { + if sub_ids.contains_key(&subscription_id) { + tracing::error!( + "Subscription closed before EndOfStoredEvents: {}", + message + ); + panic!("Subscription closed before EndOfStoredEvents: {message}"); + } + } + + RelayPoolNotification::Message { + message: RelayMessage::EndOfStoredEvents(subscription_id), + .. + } => { + sub_ids.remove(&subscription_id); + } + + RelayPoolNotification::Message { + message: RelayMessage::Event { event, .. }, + .. + } => { + self.update_machine(&event) + .await + .expect("Failed to update machine"); + } + + _ => {} + } + } + + let sub_id = self + .client + .subscribe(self.started_at, self.machines.keys().cloned()) + .await + .expect("Failed to subscribe events"); + + loop { + let notification = notifications + .recv() + .await + .expect("Failed to receive notification"); + tracing::debug!("Received notification: {:?}", notification); + + match notification { + RelayPoolNotification::Shutdown => panic!("Relay pool shutdown"), + + RelayPoolNotification::Message { + message: + RelayMessage::Closed { + message, + subscription_id, + }, + .. + } if subscription_id == sub_id => { + tracing::error!("Subscription closed: {}", message); + panic!("Subscription closed: {message}"); + } + + RelayPoolNotification::Message { + message: RelayMessage::EndOfStoredEvents(subscription_id), + .. + } if subscription_id == sub_id => {} + + RelayPoolNotification::Message { + message: + RelayMessage::Event { + event, + subscription_id, + }, + .. + } if subscription_id == sub_id => { + let Ok(message) = + serde_json::from_str::(&event.content) + else { + tracing::error!("Failed to parse message: {:?}", event); + continue; + }; + + self.handle_message(&event, &message) + .await + .expect("Failed to handle message"); + } + + _ => {} + } + } + }; + + futures::join!(relay_checker, message_handler); + } + + async fn handle_message( + &mut self, + event: &Event, + message: &DephyDechargeMessage, + ) -> Result<(), Error> { + match message { + DephyDechargeMessage::Request { + to_status, + initial_request, + reason, + payload, + } => { + if event.pubkey != self.admin_pubkey + && *reason != DephyDechargeStatusReason::UserRequest + { + tracing::error!( + "User can only use reason UserRequest, skip event: {:?}", + event + ); + } + + let Some(mention) = extract_mention(event) else { + tracing::error!("Machine not mentioned in event, skip event: {:?}", event); + return Ok(()); + }; + + let Ok(machine_pubkey) = PublicKey::parse(mention) else { + tracing::error!("Failed to parse machine pubkey, skip event: {:?}", mention); + return Ok(()); + }; + + let Some(machine) = self.machines.get(&machine_pubkey) else { + tracing::error!("Machine not controlled by us, skip event: {:?}", mention); + return Ok(()); + }; + + if machine.status == *to_status { + tracing::error!( + "Machine already in requested status, skip event: {:?}", + event + ); + return Ok(()); + } + + if *to_status == DephyDechargeStatus::Available { + if *reason == DephyDechargeStatusReason::UserRequest { + tracing::error!( + "User cannot manually stop machine, skip event: {:?}", + event + ); + return Ok(()); + } + + if let Some(ref original_request) = machine.initial_request { + if original_request != initial_request { + tracing::error!( + "Machine already in working status with different request, skip event: {:?}", + event + ); + return Ok(()); + } + } + } + + let Ok(parsed_payload) = + serde_json::from_str::(payload) + else { + tracing::error!("Failed to parse payload, skip event: {:?}", payload); + return Ok(()); + }; + + match dephy_balance_payment_sdk::check_eligible( + &self.solana_rpc_url, + &parsed_payload.user, + parsed_payload.nonce, + PREPAID_AMOUNT, + &parsed_payload.recover_info, + ) + .await + { + Err(e) => { + tracing::error!( + "Failed to check eligible, error: {:?} skip event: {:?}", + e, + event + ); + return Ok(()); + } + + Ok(false) => { + tracing::error!("User not eligible, skip event: {:?}", event); + return Ok(()); + } + Ok(true) => {} + } + + self.client + .send_event(mention, &DephyDechargeMessage::Status { + status: *to_status, + reason: *reason, + initial_request: event.id, + payload: serde_json::to_string(&DephyDechargeMessageStatusPayload { + user: parsed_payload.user.clone(), + nonce: parsed_payload.nonce, + recover_info: parsed_payload.recover_info.clone(), + })?, + }) + .await?; + + // TODO: Should check this by machine api + if *to_status == DephyDechargeStatus::Working { + let client = self.client.clone(); + let mention = mention.to_string(); + let event_id = event.id; + tokio::spawn(async move { + tokio::time::sleep(std::time::Duration::from_secs(60)).await; + client + .send_event(&mention, &DephyDechargeMessage::Status { + status: DephyDechargeStatus::Available, + reason: DephyDechargeStatusReason::UserBehaviour, + initial_request: event_id, + payload: serde_json::to_string( + &DephyDechargeMessageStatusPayload { + user: parsed_payload.user.clone(), + nonce: parsed_payload.nonce, + recover_info: parsed_payload.recover_info, + }, + ) + .unwrap(), + }) + .await + .unwrap(); + }); + } + } + DephyDechargeMessage::Status { .. } => self.update_machine(event).await?, + } + Ok(()) + } +} diff --git a/dephy-vending_machine-examples/examples/decharge-controller/src/node/mod.rs b/dephy-vending_machine-examples/examples/decharge-controller/src/node/mod.rs new file mode 100644 index 0000000..e4ecd47 --- /dev/null +++ b/dephy-vending_machine-examples/examples/decharge-controller/src/node/mod.rs @@ -0,0 +1,3 @@ +mod message_handler; + +pub use message_handler::MessageHandler; diff --git a/dephy-vending_machine-examples/examples/decharge-controller/src/relay_client.rs b/dephy-vending_machine-examples/examples/decharge-controller/src/relay_client.rs new file mode 100644 index 0000000..de4b2b8 --- /dev/null +++ b/dephy-vending_machine-examples/examples/decharge-controller/src/relay_client.rs @@ -0,0 +1,182 @@ +use nostr::Event; +use nostr::EventBuilder; +use nostr::Filter; +use nostr::Keys; +use nostr::PublicKey; +use nostr::SingleLetterTag; +use nostr::SubscriptionId; +use nostr::Tag; +use nostr::Timestamp; +use nostr_sdk::prelude::ReqExitPolicy; +use nostr_sdk::Client; +use nostr_sdk::RelayPoolNotification; +use nostr_sdk::RelayStatus; +use nostr_sdk::SubscribeAutoCloseOptions; +use tokio::sync::broadcast::Receiver; + +const EVENT_KIND: nostr::Kind = nostr::Kind::Custom(1573); +const MENTION_TAG: SingleLetterTag = SingleLetterTag::lowercase(nostr::Alphabet::P); +const SESSION_TAG: SingleLetterTag = SingleLetterTag::lowercase(nostr::Alphabet::S); + +#[derive(Debug, thiserror::Error)] +#[non_exhaustive] +pub enum Error { + #[error("Nostr client error: {0}")] + NostrClient(#[from] nostr_sdk::client::Error), + #[error("Serde json error: {0}")] + SerdeJson(#[from] serde_json::Error), + #[error("Send event error: {0}")] + SendEvent(String), +} + +#[derive(Clone)] +pub struct RelayClient { + client: Client, + session: String, +} + +impl RelayClient { + pub async fn new( + nostr_relay: &str, + keys: &Keys, + session: &str, + max_notification_size: usize, + ) -> Result { + let client_opts = + nostr_sdk::Options::default().notification_channel_size(max_notification_size); + + let client = Client::builder() + .signer(keys.clone()) + .opts(client_opts) + .build(); + + client.add_relay(nostr_relay).await?; + client.connect().await; + + Ok(Self { + client, + session: session.to_string(), + }) + } + + pub async fn run_relay_checker(self, interval: std::time::Duration) { + loop { + tokio::time::sleep(interval).await; + + let connected_relay_count = self + .client + .relays() + .await + .values() + .filter(|relay| relay.status() == RelayStatus::Connected) + .count(); + + if connected_relay_count == 0 { + panic!("Lost connection to relay"); + } + } + } + + pub fn notifications(&self) -> Receiver { + self.client.notifications() + } + + pub async fn subscribe_last_event( + &self, + until: Timestamp, + author: Option<&PublicKey>, + mention: &PublicKey, + ) -> Result { + let mut filter = Filter::new(); + + filter = filter + .kind(EVENT_KIND) + .until(until) + .custom_tag(SESSION_TAG, [&self.session]) + .custom_tag(MENTION_TAG, [mention.to_hex()]) + .limit(1); + + if let Some(author) = author { + filter = filter.author(*author) + } + + let close_option = + SubscribeAutoCloseOptions::default().exit_policy(ReqExitPolicy::ExitOnEOSE); + let output = self + .client + .subscribe(vec![filter], Some(close_option)) + .await?; + + Ok(output.id().clone()) + } + + pub async fn subscribe( + &self, + since: Timestamp, + mentions: I, + ) -> Result + where + I: IntoIterator, + { + let filter = Filter::new() + .kind(EVENT_KIND) + .since(since) + .custom_tag(SESSION_TAG, [&self.session]) + .custom_tag(MENTION_TAG, mentions.into_iter().map(|pk| pk.to_hex())); + + let output = self.client.subscribe(vec![filter], None).await?; + + Ok(output.id().clone()) + } + + pub async fn subscribe_all(&self, since: Option) -> Result { + let mut filter = Filter::new() + .kind(EVENT_KIND) + .custom_tag(SESSION_TAG, [&self.session]); + + if let Some(since) = since { + filter = filter.since(since); + } + + let output = self.client.subscribe(vec![filter], None).await?; + + Ok(output.id().clone()) + } + + pub async fn send_event(&self, to: &str, message: &M) -> Result<(), Error> + where M: serde::Serialize + std::fmt::Debug { + let content = serde_json::to_string(message)?; + + let event_builder = EventBuilder::new(EVENT_KIND, content).tags([ + Tag::parse(["s".to_string(), self.session.clone()]).unwrap(), + Tag::parse(["p".to_string(), to.to_string()]).unwrap(), + ]); + + let res = self.client.send_event_builder(event_builder).await?; + + if !res.failed.is_empty() { + for (relay_url, err) in res.failed.iter() { + tracing::error!("failed to send event to {} err: {:?}", relay_url, err); + } + return Err(Error::SendEvent(format!( + "Failed to send event {message:?} to relay" + ))); + } + + Ok(()) + } +} + +pub fn extract_mention(event: &Event) -> Option<&str> { + event + .tags + .iter() + .filter_map(|tag| { + if tag.single_letter_tag() == Some(MENTION_TAG) { + tag.content() + } else { + None + } + }) + .next() +} diff --git a/dephy-vending_machine-examples/examples/decharge-controller/src/server/message_handler.rs b/dephy-vending_machine-examples/examples/decharge-controller/src/server/message_handler.rs new file mode 100644 index 0000000..0d87660 --- /dev/null +++ b/dephy-vending_machine-examples/examples/decharge-controller/src/server/message_handler.rs @@ -0,0 +1,254 @@ +use nostr::Event; +use nostr::PublicKey; +use nostr::RelayMessage; +use nostr::Timestamp; +use nostr_sdk::RelayPoolNotification; +use tokio::sync::oneshot; + +use crate::message::DephyDechargeMessage; +use crate::message::DephyDechargeMessageStatusPayload; +use crate::message::DephyDechargeStatus; +use crate::message::DephyDechargeStatusReason; +use crate::relay_client::extract_mention; +use crate::server::State; +use crate::RelayClient; + +/// MAX_DEVIATION_SECONDS * 4 +/// MAX_DEVIATION_SECONDS is from dephy_messaging_network crate. +const TIME_BACKTRACE_OF_INITIAL_RETRIEVE: std::time::Duration = + std::time::Duration::from_secs(30 * 4); + +const PREPAID_AMOUNT: u64 = 10_000_000; +const TRANSFER_AMOUNT: u64 = 5_000_000; + +#[derive(Debug, thiserror::Error)] +#[non_exhaustive] +pub enum Error { + #[error("IO error: {0}")] + Io(#[from] std::io::Error), + #[error("Server state error: {0}")] + State(#[from] crate::server::state::Error), + #[error("Serde json error: {0}")] + SerdeJson(#[from] serde_json::Error), + #[error("Nostr key error: {0}")] + NostrKey(#[from] nostr::key::Error), + #[error("Relay client error: {0}")] + RelayClient(#[from] crate::relay_client::Error), +} + +pub struct MessageHandler { + client: RelayClient, + state: State, + solana_rpc_url: String, + solana_keypair_path: String, + initial_notifier: Option>, +} + +impl MessageHandler { + pub fn new( + client: RelayClient, + state: State, + solana_rpc_url: &str, + solana_keypair_path: &str, + initial_notifier: Option>, + ) -> Self { + Self { + client, + state, + solana_rpc_url: solana_rpc_url.to_string(), + solana_keypair_path: solana_keypair_path.to_string(), + initial_notifier, + } + } + + pub async fn run(mut self) { + let last_processed_event = self + .state + .db_get_last_processed_event() + .await + .expect("Failed to get last processed event"); + + let since = last_processed_event.as_ref().map(|event| { + Timestamp::from_secs(event.created_at as u64) - TIME_BACKTRACE_OF_INITIAL_RETRIEVE + }); + let last_event_id = last_processed_event.map(|event| event.event_id); + + let mut notifications = self.client.notifications(); + self.client + .subscribe_all(since) + .await + .expect("Failed to subscribe events"); + + let checking_client = self.client.clone(); + let relay_checker = async move { + checking_client + .run_relay_checker(std::time::Duration::from_secs(10)) + .await + }; + + let message_handler = async move { + let mut reached_last_event = last_event_id.is_none(); + + loop { + let notification = notifications + .recv() + .await + .expect("Failed to receive notification"); + tracing::debug!("Received notification: {:?}", notification); + + match notification { + RelayPoolNotification::Shutdown => panic!("Relay pool shutdown"), + RelayPoolNotification::Message { + message: RelayMessage::Closed { message, .. }, + .. + } => { + tracing::error!("Subscription closed: {}", message); + panic!("Subscription closed: {message}"); + } + RelayPoolNotification::Message { + message: RelayMessage::EndOfStoredEvents { .. }, + .. + } => { + if !reached_last_event { + tracing::error!( + "Not reached last processed event: {last_event_id:?}, but received end of stored events" + ); + panic!("Not reached last processed event"); + } + + tracing::info!("End of stored events, notifying the checker"); + + let Some(notifier) = self.initial_notifier.take() else { + tracing::info!("No initial_notifier found, will skip notifying"); + continue; + }; + + notifier.send(()).expect("Failed to notify checker start"); + } + RelayPoolNotification::Message { + message: RelayMessage::Event { event, .. }, + .. + } => { + if !reached_last_event { + let last_event_id = last_event_id.as_deref().unwrap(); + + if event.id.to_hex() == last_event_id { + tracing::info!( + "Reached last processed event: {last_event_id}, start handling events" + ); + reached_last_event = true; + } + + continue; + } + + let Ok(message) = + serde_json::from_str::(&event.content) + else { + tracing::error!("Failed to parse message: {:?}", event); + continue; + }; + + self.handle_message(&event, &message) + .await + .expect("Failed to handle message"); + } + _ => {} + } + } + }; + + futures::join!(relay_checker, message_handler); + } + + async fn handle_message( + &self, + event: &Event, + message: &DephyDechargeMessage, + ) -> Result<(), Error> { + tracing::debug!("Handling message: {:?}", message); + let received_id = self + .state + .db_record_received_event(&event.id.to_hex(), event.created_at.as_u64() as i64) + .await?; + + match message { + DephyDechargeMessage::Status { + status: DephyDechargeStatus::Working, + reason: DephyDechargeStatusReason::UserRequest, + initial_request, + payload, + } => { + let Some(mention) = extract_mention(event) else { + tracing::error!("Machine not mentioned in event, skip event: {:?}", event); + return Ok(()); + }; + + if PublicKey::parse(mention).is_err() { + tracing::error!("Failed to parse machine pubkey, skip event: {:?}", mention); + return Ok(()); + }; + + let parsed_payload = + serde_json::from_str::(payload)?; + + if let Err(e) = dephy_balance_payment_sdk::lock( + &self.solana_rpc_url, + &self.solana_keypair_path, + &parsed_payload.user, + PREPAID_AMOUNT, + &parsed_payload.recover_info, + ) + .await + { + tracing::error!("Failed to lock error: {:?} event: {:?}", e, event); + + self.client + .send_event(mention, &DephyDechargeMessage::Request { + to_status: DephyDechargeStatus::Available, + reason: DephyDechargeStatusReason::LockFailed, + initial_request: *initial_request, + payload: payload.to_string(), + }) + .await? + } + } + DephyDechargeMessage::Status { + status: DephyDechargeStatus::Available, + reason: DephyDechargeStatusReason::UserBehaviour, + payload, + .. + } => { + let Some(mention) = extract_mention(event) else { + tracing::error!("Machine not mentioned in event, skip event: {:?}", event); + return Ok(()); + }; + + if PublicKey::parse(mention).is_err() { + tracing::error!("Failed to parse machine pubkey, skip event: {:?}", mention); + return Ok(()); + }; + + let parsed_payload = + serde_json::from_str::(payload)?; + + if let Err(e) = dephy_balance_payment_sdk::settle( + &self.solana_rpc_url, + &self.solana_keypair_path, + &parsed_payload.user, + parsed_payload.nonce, + TRANSFER_AMOUNT, + ) + .await + { + tracing::error!("Failed to settle error: {:?} event: {:?}", e, event); + } + } + _ => {} + } + + self.state.db_record_event_processed(received_id).await?; + + Ok(()) + } +} diff --git a/dephy-vending_machine-examples/examples/decharge-controller/src/server/mod.rs b/dephy-vending_machine-examples/examples/decharge-controller/src/server/mod.rs new file mode 100644 index 0000000..ad1f7a3 --- /dev/null +++ b/dephy-vending_machine-examples/examples/decharge-controller/src/server/mod.rs @@ -0,0 +1,5 @@ +mod message_handler; +mod state; + +pub use message_handler::MessageHandler; +pub use state::State; diff --git a/dephy-vending_machine-examples/examples/decharge-controller/src/server/state.rs b/dephy-vending_machine-examples/examples/decharge-controller/src/server/state.rs new file mode 100644 index 0000000..ff4bb11 --- /dev/null +++ b/dephy-vending_machine-examples/examples/decharge-controller/src/server/state.rs @@ -0,0 +1,123 @@ +use sea_query::Expr; +use sea_query::Iden; +use sea_query::Order; +use sea_query::PostgresQueryBuilder; +use sea_query::Query; +use sea_query::SimpleExpr; +use sea_query::Value; +use sea_query_binder::SqlxBinder; +use sea_query_binder::SqlxValues; + +#[derive(Debug, thiserror::Error)] +#[non_exhaustive] +pub enum Error { + #[error("SQL build error: {0}")] + SqlBuild(#[from] sea_query::error::Error), + #[error("SQL execute error: {0}")] + SqlExecute(#[from] sqlx::Error), +} + +#[derive(Iden, Clone, Copy)] +enum ReceivedEvents { + Id, + Table, + EventId, + CreatedAt, + IsProcessed, +} + +const RECEIVED_EVENT_RECORD_COLUMNS: [ReceivedEvents; 3] = [ + ReceivedEvents::EventId, + ReceivedEvents::CreatedAt, + ReceivedEvents::IsProcessed, +]; +#[derive(sqlx::FromRow, Debug)] +pub struct ReceivedEventRecord { + pub event_id: String, + pub created_at: i64, + pub is_processed: bool, +} + +pub struct State { + db: sqlx::PgPool, +} + +impl State { + pub fn new(db: sqlx::PgPool) -> Self { + Self { db } + } + + pub async fn db_get_last_processed_event(&self) -> Result, Error> { + let (sql, values) = Query::select() + .columns(RECEIVED_EVENT_RECORD_COLUMNS) + .from(ReceivedEvents::Table) + .and_where(Expr::col(ReceivedEvents::IsProcessed).eq(true)) + // Note: Should not use created_at for sorting. + // It is not unique and the messages may not be received in the order of creation. + .order_by(ReceivedEvents::Id, Order::Desc) + .limit(1) + .build_sqlx(PostgresQueryBuilder); + + tracing::debug!("will execute: {sql} with {values:?}"); + + let row = sqlx::query_as_with::<_, ReceivedEventRecord, _>(&sql, values) + .fetch_optional(&self.db) + .await?; + + Ok(row) + } + + pub async fn db_record_received_event( + &self, + event_id: &str, + created_at: i64, + ) -> Result { + let (sql, values) = Query::insert() + .into_table(ReceivedEvents::Table) + .columns([ + ReceivedEvents::EventId, + ReceivedEvents::CreatedAt, + ReceivedEvents::IsProcessed, + ]) + .values( + [ + Value::from(event_id), + Value::from(created_at), + Value::from(false), + ] + .map(SimpleExpr::Value), + )? + .returning(Query::returning().columns([ReceivedEvents::Id])) + .build_sqlx(PostgresQueryBuilder); + + let row = sqlx::query_as_with::<_, (i64,), _>(&sql, values) + .fetch_one(&self.db) + .await?; + + Ok(row.0) + } + + // This method is isolated because updating the event to processed may be part of a transaction. + fn sql_received_event_is_processed(received_id: i64) -> (String, SqlxValues) { + let (sql, values) = Query::update() + .table(ReceivedEvents::Table) + .values([( + ReceivedEvents::IsProcessed, + SimpleExpr::Value(Value::from(true)), + )]) + .and_where(Expr::col(ReceivedEvents::Id).eq(received_id)) + .build_sqlx(PostgresQueryBuilder); + (sql, values) + } + + pub async fn db_record_event_processed(&self, received_id: i64) -> Result<(), Error> { + let (received_sql, received_values) = State::sql_received_event_is_processed(received_id); + tracing::debug!("will execute: {received_sql} with {received_values:?}"); + + sqlx::query_with(&received_sql, received_values) + .execute(&self.db) + .await?; + + Ok(()) + } +} diff --git a/dephy-vending_machine-examples/examples/gacha-controller/Cargo.toml b/dephy-vending_machine-examples/examples/gacha-controller/Cargo.toml new file mode 100644 index 0000000..4252cea --- /dev/null +++ b/dephy-vending_machine-examples/examples/gacha-controller/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "dephy-gacha-controller" +version = "0.1.0" +edition = "2021" +license.workspace = true + +[dependencies] +clap = { workspace = true } +dephy-balance-payment-sdk = { workspace = true } +futures = { workspace = true } +nostr = { workspace = true } +nostr-sdk = { workspace = true } +serde = { workspace = true } +serde_json = { workspace = true } +thiserror = { workspace = true } +tokio = { workspace = true, features = ["process", "rt-multi-thread"] } +tracing = { workspace = true } +tracing-subscriber = { workspace = true, features = ["env-filter"] } diff --git a/dephy-vending_machine-examples/examples/gacha-controller/README.md b/dephy-vending_machine-examples/examples/gacha-controller/README.md new file mode 100644 index 0000000..df35ed2 --- /dev/null +++ b/dephy-vending_machine-examples/examples/gacha-controller/README.md @@ -0,0 +1,52 @@ +# dephy-gacha-controller + +## Prepare + +In this example, you should have a messaging network running on `ws://127.0.0.1:8000`. +You can modify `--nostr-relay` if it is running on a different address. + +To run a messaging network you need a postgresql database with schema: + +```sql +CREATE TABLE IF NOT EXISTS events ( + id bigserial PRIMARY KEY, + event_id character varying NOT NULL, + prev_event_id character varying NOT NULL, + pubkey character varying NOT NULL, + created_at bigint NOT NULL, + original character varying NOT NULL, + "session" character varying NOT NULL, + mention character varying, + + CONSTRAINT events_unique_event_id + UNIQUE (event_id), + + CONSTRAINT events_unique_pubkey_session_prev_event_id + UNIQUE (pubkey, session, prev_event_id) +); +``` + +To run a messaging network by docker: + +```shell +docker run --name dephy-messaging-network --restart=always --network="host" -d dephyio/dephy-messaging-network:master serve --pg-url 'postgresql://:@
/' +``` + +## Run Controller (this is on gacha equipment side) + +The controller daemon need your solana keypair. + +```shell +mkdir data +# copy your keypair to data/solana-keypair +``` + +```shell +cargo run --bin dephy-gacha-controller -- --nostr-relay ws://127.0.0.1:8000 --machine-pubkeys 91550af28891a6ac6c73e0d415ed5ee9ea5603ef6d276df623a8b80254519ab2 --admin-pubkey --solana-rpc-url https://api.devnet.solana.com +``` + +## Cli Example (it simulates the process of inserting a coin) + +```shell +cargo run --example cli -- --nostr-relay ws://127.0.0.1:8000 --machine-pubkey 91550af28891a6ac6c73e0d415ed5ee9ea5603ef6d276df623a8b80254519ab2 --user --nonce --recover-info +``` diff --git a/dephy-vending_machine-examples/examples/gacha-controller/examples/cli.rs b/dephy-vending_machine-examples/examples/gacha-controller/examples/cli.rs new file mode 100644 index 0000000..77576c6 --- /dev/null +++ b/dephy-vending_machine-examples/examples/gacha-controller/examples/cli.rs @@ -0,0 +1,158 @@ +use std::path::PathBuf; + +use clap::value_parser; +use clap::Arg; +use clap::ArgAction; +use clap::ArgMatches; +use clap::Command; +use dephy_gacha_controller::message::DephyGachaMessage; +use dephy_gacha_controller::message::DephyGachaMessageRequestPayload; +use dephy_gacha_controller::message::DephyGachaStatus; +use dephy_gacha_controller::message::DephyGachaStatusReason; +use nostr::Keys; +use nostr::Timestamp; +use nostr_sdk::EventId; + +const SESSION: &str = "dephy-gacha-controller"; + +fn parse_args() -> Command { + Command::new("dephy-gacha-controller-cli") + .arg_required_else_help(true) + .about("Dephy gacha controller") + .version(dephy_gacha_controller::VERSION) + .arg( + Arg::new("NOSTR_RELAY") + .long("nostr-relay") + .num_args(1) + .required(true) + .action(ArgAction::Set) + .help("Nostr relay address"), + ) + .arg( + Arg::new("KEY_FILE") + .long("key-file") + .num_args(1) + .default_value("data/key") + .value_parser(value_parser!(PathBuf)) + .action(ArgAction::Set) + .help("Path to the file containing the hex or bech32 secret key"), + ) + .arg( + Arg::new("MACHINE_PUBKEY") + .long("machine-pubkey") + .num_args(1) + .required(true) + .action(ArgAction::Set) + .help("Machine public keys, comma separated"), + ) + .arg( + Arg::new("user") + .long("user") + .num_args(1) + .required(true) + .action(ArgAction::Set) + .help("User public key"), + ) + .arg( + Arg::new("nonce") + .long("nonce") + .num_args(1) + .required(true) + .value_parser(value_parser!(u64)) + .action(ArgAction::Set) + .help("Nonce"), + ) + .arg( + Arg::new("recover_info") + .long("recover-info") + .num_args(1) + .required(true) + .action(ArgAction::Set) + .help("Recover info"), + ) +} + +async fn cli(args: &ArgMatches) { + let nostr_relay = args.get_one::("NOSTR_RELAY").unwrap(); + let key_file_path = args.get_one::("KEY_FILE").unwrap(); + let keys = read_or_generate_keypair(key_file_path); + let machine_pubkey = args + .get_one::("MACHINE_PUBKEY") + .unwrap() + .parse() + .expect("Invalid machine pubkey"); + let user = args.get_one::("user").unwrap(); + let nonce = args.get_one::("nonce").unwrap(); + let recover_info = args.get_one::("recover_info").unwrap(); + + let client = dephy_gacha_controller::RelayClient::new(nostr_relay, &keys, SESSION, 4096) + .await + .expect("Failed to connect to relay"); + + let mut notifications = client.notifications(); + client + .subscribe(Timestamp::now(), [machine_pubkey]) + .await + .expect("Failed to subscribe"); + + let handler = tokio::spawn(async move { + loop { + let notification = notifications.recv().await; + tracing::info!("Received notification: {:?}", notification); + } + }); + + let payload = serde_json::to_string(&DephyGachaMessageRequestPayload { + user: user.clone(), + nonce: *nonce, + recover_info: recover_info.clone(), + }) + .expect("Failed to serialize payload"); + + client + .send_event(&machine_pubkey.to_hex(), &DephyGachaMessage::Request { + to_status: DephyGachaStatus::Working, + reason: DephyGachaStatusReason::UserRequest, + initial_request: EventId::all_zeros(), + payload, + }) + .await + .expect("Failed to send event"); + + handler.await.expect("Notification handler failed"); +} + +fn read_or_generate_keypair(path: &PathBuf) -> Keys { + let keys = std::fs::read_to_string(path) + .map(|content| content.trim().parse().expect("Invalid key")) + .unwrap_or_else(|_| { + tracing::info!( + "Key file not found, generating a new one at: {}", + path.display() + ); + let keys = Keys::generate(); + std::fs::write(path, keys.secret_key().to_secret_hex()) + .unwrap_or_else(|e| panic!("Failed to write key {}: {e:?}", path.display())); + keys + }); + + let pubkey_path = path.with_extension("pub"); + std::fs::write(&pubkey_path, keys.public_key().to_hex()).unwrap_or_else(|e| { + panic!( + "Failed to write public key {}: {e:?}", + pubkey_path.display() + ) + }); + + keys +} + +#[tokio::main] +async fn main() { + let _ = tracing_subscriber::fmt() + .with_env_filter(tracing_subscriber::EnvFilter::from_default_env()) + .try_init(); + + let cmd = parse_args(); + cli(&cmd.get_matches()).await; +} diff --git a/dephy-vending_machine-examples/examples/gacha-controller/src/lib.rs b/dephy-vending_machine-examples/examples/gacha-controller/src/lib.rs new file mode 100644 index 0000000..210058e --- /dev/null +++ b/dephy-vending_machine-examples/examples/gacha-controller/src/lib.rs @@ -0,0 +1,8 @@ +pub mod message; +pub mod node; +mod relay_client; + +/// dephy-gacha-controller version +pub const VERSION: &str = env!("CARGO_PKG_VERSION"); + +pub use relay_client::RelayClient; diff --git a/dephy-vending_machine-examples/examples/gacha-controller/src/main.rs b/dephy-vending_machine-examples/examples/gacha-controller/src/main.rs new file mode 100644 index 0000000..47078d1 --- /dev/null +++ b/dephy-vending_machine-examples/examples/gacha-controller/src/main.rs @@ -0,0 +1,147 @@ +use std::path::PathBuf; + +use clap::value_parser; +use clap::Arg; +use clap::ArgAction; +use clap::ArgMatches; +use clap::Command; +use nostr::Keys; + +const SESSION: &str = "dephy-gacha-controller"; + +fn parse_args() -> Command { + Command::new("dephy-gacha-controller-node") + .arg_required_else_help(true) + .about("Dephy gacha controller node daemon") + .version(dephy_gacha_controller::VERSION) + .arg( + Arg::new("NOSTR_RELAY") + .long("nostr-relay") + .num_args(1) + .required(true) + .action(ArgAction::Set) + .help("Nostr relay address"), + ) + .arg( + Arg::new("KEY_FILE") + .long("key-file") + .num_args(1) + .default_value("data/key") + .value_parser(value_parser!(PathBuf)) + .action(ArgAction::Set) + .help("Path to the file containing the hex or bech32 secret key"), + ) + .arg( + Arg::new("ADMIN_PUBKEY") + .long("admin-pubkey") + .num_args(1) + .required(true) + .action(ArgAction::Set) + .help("Admin public key"), + ) + .arg( + Arg::new("MACHINE_PUBKEYS") + .long("machine-pubkeys") + .num_args(1) + .required(true) + .action(ArgAction::Set) + .help("Machine public keys, comma separated"), + ) + .arg( + Arg::new("SOLANA_RPC_URL") + .long("solana-rpc-url") + .num_args(1) + .required(true) + .action(ArgAction::Set) + .help("Solana RPC URL"), + ) + .arg( + Arg::new("SOLANA_KEYPAIR") + .long("solana-keypair") + .num_args(1) + .default_value("data/solana-keypair") + .value_parser(value_parser!(PathBuf)) + .action(ArgAction::Set) + .help("Solana keypair path"), + ) +} + +async fn controller(args: &ArgMatches) { + let nostr_relay = args.get_one::("NOSTR_RELAY").unwrap(); + let key_file_path = args.get_one::("KEY_FILE").unwrap(); + let keys = read_or_generate_keypair(key_file_path); + let admin_pubkey = args + .get_one::("ADMIN_PUBKEY") + .unwrap() + .parse() + .expect("Invalid admin pubkey"); + let machine_pubkeys = args + .get_one::("MACHINE_PUBKEYS") + .unwrap() + .split(',') + .map(|s| s.parse().expect("Invalid machine pubkey")) + .collect(); + let solana_rpc_url = args.get_one::("SOLANA_RPC_URL").unwrap(); + let solana_keypair_path = args.get_one::("SOLANA_KEYPAIR").unwrap(); + if !solana_keypair_path.exists() { + panic!( + "Solana keypair file not found: {}", + solana_keypair_path.display() + ); + } + + println!("nostr relay: {}", nostr_relay); + println!("pubkey: {}", keys.public_key()); + + let client = dephy_gacha_controller::RelayClient::new(nostr_relay, &keys, SESSION, 4096) + .await + .expect("Failed to connect to relay"); + + let message_handler = dephy_gacha_controller::node::MessageHandler::new( + client, + solana_rpc_url, + solana_keypair_path + .to_str() + .expect("Invalid solana keypair path"), + keys.public_key(), + admin_pubkey, + machine_pubkeys, + ); + + message_handler.run().await +} + +fn read_or_generate_keypair(path: &PathBuf) -> Keys { + let keys = std::fs::read_to_string(path) + .map(|content| content.trim().parse().expect("Invalid key")) + .unwrap_or_else(|_| { + tracing::info!( + "Key file not found, generating a new one at: {}", + path.display() + ); + let keys = Keys::generate(); + std::fs::write(path, keys.secret_key().to_secret_hex()) + .unwrap_or_else(|e| panic!("Failed to write key {}: {e:?}", path.display())); + keys + }); + + let pubkey_path = path.with_extension("pub"); + std::fs::write(&pubkey_path, keys.public_key().to_hex()).unwrap_or_else(|e| { + panic!( + "Failed to write public key {}: {e:?}", + pubkey_path.display() + ) + }); + + keys +} + +#[tokio::main] +async fn main() { + let _ = tracing_subscriber::fmt() + .with_env_filter(tracing_subscriber::EnvFilter::from_default_env()) + .try_init(); + + let cmd = parse_args(); + controller(&cmd.get_matches()).await; +} diff --git a/dephy-vending_machine-examples/examples/gacha-controller/src/message.rs b/dephy-vending_machine-examples/examples/gacha-controller/src/message.rs new file mode 100644 index 0000000..b8a7cd3 --- /dev/null +++ b/dephy-vending_machine-examples/examples/gacha-controller/src/message.rs @@ -0,0 +1,50 @@ +use nostr::EventId; +use serde::Deserialize; +use serde::Serialize; + +#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)] +#[repr(u8)] +pub enum DephyGachaStatus { + Available = 1, + Working = 2, +} + +#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)] +#[repr(u8)] +pub enum DephyGachaStatusReason { + UserRequest = 1, + AdminRequest = 2, + UserBehaviour = 3, + Reset = 4, + LockFailed = 5, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum DephyGachaMessage { + Request { + to_status: DephyGachaStatus, + reason: DephyGachaStatusReason, + initial_request: EventId, + payload: String, + }, + Status { + status: DephyGachaStatus, + reason: DephyGachaStatusReason, + initial_request: EventId, + payload: String, + }, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct DephyGachaMessageRequestPayload { + pub user: String, + pub nonce: u64, + pub recover_info: String, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct DephyGachaMessageStatusPayload { + pub user: String, + pub nonce: u64, + pub recover_info: String, +} diff --git a/dephy-vending_machine-examples/examples/gacha-controller/src/node/message_handler.rs b/dephy-vending_machine-examples/examples/gacha-controller/src/node/message_handler.rs new file mode 100644 index 0000000..465ff06 --- /dev/null +++ b/dephy-vending_machine-examples/examples/gacha-controller/src/node/message_handler.rs @@ -0,0 +1,378 @@ +use std::collections::HashMap; +use std::collections::HashSet; + +use nostr::Event; +use nostr::EventId; +use nostr::PublicKey; +use nostr::RelayMessage; +use nostr::Timestamp; +use nostr_sdk::RelayPoolNotification; + +use crate::message::DephyGachaMessage; +use crate::message::DephyGachaMessageRequestPayload; +use crate::message::DephyGachaMessageStatusPayload; +use crate::message::DephyGachaStatus; +use crate::message::DephyGachaStatusReason; +use crate::relay_client::extract_mention; +use crate::RelayClient; + +const PAY_AMOUNT: u64 = 5_000_000; + +#[derive(Debug, thiserror::Error)] +#[non_exhaustive] +pub enum Error { + #[error("Serde json error: {0}")] + SerdeJson(#[from] serde_json::Error), + #[error("Nostr key error: {0}")] + NostrKey(#[from] nostr::key::Error), + #[error("Relay client error: {0}")] + RelayClient(#[from] crate::relay_client::Error), + #[error("Machine not mentioned in event: {0:?}")] + MachineNotMentioned(Event), + #[error("The machine mentioned by event is not controlled by us: {0:?}")] + MachineNotControlled(Event), + #[error("Only support status event when update machine, but got: {0:?}")] + OnlySupportStatusEventWhenUpdateMachine(Event), +} + +pub struct Machine { + #[allow(dead_code)] + pubkey: PublicKey, + status: DephyGachaStatus, + initial_request: Option, +} + +pub struct MessageHandler { + client: RelayClient, + solana_rpc_url: String, + solana_keypair_path: String, + controller_pubkey: PublicKey, + admin_pubkey: PublicKey, + machines: HashMap, + started_at: Timestamp, +} + +impl MessageHandler { + pub fn new( + client: RelayClient, + solana_rpc_url: &str, + solana_keypair_path: &str, + controller_pubkey: PublicKey, + admin_pubkey: PublicKey, + machine_pubkeys: HashSet, + ) -> Self { + let started_at = Timestamp::now(); + let machines = machine_pubkeys + .into_iter() + .map(|pubkey| { + (pubkey, Machine { + pubkey, + status: DephyGachaStatus::Available, + initial_request: None, + }) + }) + .collect(); + + Self { + client, + solana_rpc_url: solana_rpc_url.to_string(), + solana_keypair_path: solana_keypair_path.to_string(), + controller_pubkey, + admin_pubkey, + machines, + started_at, + } + } + + pub async fn update_machine(&mut self, event: &Event) -> Result<(), Error> { + let mention = PublicKey::parse( + extract_mention(event).ok_or_else(|| Error::MachineNotMentioned(event.clone()))?, + )?; + + let machine = self + .machines + .get_mut(&mention) + .ok_or_else(|| Error::MachineNotControlled(event.clone()))?; + + let message = serde_json::from_str::(&event.content)?; + + match message { + DephyGachaMessage::Request { .. } => { + return Err(Error::OnlySupportStatusEventWhenUpdateMachine( + event.clone(), + )) + } + + DephyGachaMessage::Status { + status, + initial_request, + .. + } => { + machine.status = status; + machine.initial_request = Some(initial_request); + } + } + + Ok(()) + } + + pub async fn run(mut self) { + let mut notifications = self.client.notifications(); + + let checking_client = self.client.clone(); + let relay_checker = async move { + checking_client + .run_relay_checker(std::time::Duration::from_secs(10)) + .await + }; + + let message_handler = async move { + let mut sub_ids = HashMap::new(); + + for machine_pubkey in self.machines.keys().copied() { + let sub_id = self + .client + .subscribe_last_event( + self.started_at, + Some(&self.controller_pubkey), + &machine_pubkey, + ) + .await + .expect("Failed to subscribe events"); + + sub_ids.insert(sub_id, machine_pubkey); + } + + while !sub_ids.is_empty() { + let notification = notifications + .recv() + .await + .expect("Failed to receive notification"); + tracing::debug!("Received notification: {:?}", notification); + + match notification { + RelayPoolNotification::Shutdown => panic!("Relay pool shutdown"), + + RelayPoolNotification::Message { + message: + RelayMessage::Closed { + message, + subscription_id, + }, + .. + } => { + if sub_ids.contains_key(&subscription_id) { + tracing::error!( + "Subscription closed before EndOfStoredEvents: {}", + message + ); + panic!("Subscription closed before EndOfStoredEvents: {message}"); + } + } + + RelayPoolNotification::Message { + message: RelayMessage::EndOfStoredEvents(subscription_id), + .. + } => { + sub_ids.remove(&subscription_id); + } + + RelayPoolNotification::Message { + message: RelayMessage::Event { event, .. }, + .. + } => { + self.update_machine(&event) + .await + .expect("Failed to update machine"); + } + + _ => {} + } + } + + let sub_id = self + .client + .subscribe(self.started_at, self.machines.keys().cloned()) + .await + .expect("Failed to subscribe events"); + + loop { + let notification = notifications + .recv() + .await + .expect("Failed to receive notification"); + tracing::debug!("Received notification: {:?}", notification); + + match notification { + RelayPoolNotification::Shutdown => panic!("Relay pool shutdown"), + + RelayPoolNotification::Message { + message: + RelayMessage::Closed { + message, + subscription_id, + }, + .. + } if subscription_id == sub_id => { + tracing::error!("Subscription closed: {}", message); + panic!("Subscription closed: {message}"); + } + + RelayPoolNotification::Message { + message: RelayMessage::EndOfStoredEvents(subscription_id), + .. + } if subscription_id == sub_id => {} + + RelayPoolNotification::Message { + message: + RelayMessage::Event { + event, + subscription_id, + }, + .. + } if subscription_id == sub_id => { + let Ok(message) = serde_json::from_str::(&event.content) + else { + tracing::error!("Failed to parse message: {:?}", event); + continue; + }; + + self.handle_message(&event, &message) + .await + .expect("Failed to handle message"); + } + + _ => {} + } + } + }; + + futures::join!(relay_checker, message_handler); + } + + async fn handle_message( + &mut self, + event: &Event, + message: &DephyGachaMessage, + ) -> Result<(), Error> { + match message { + DephyGachaMessage::Request { + to_status, + initial_request, + reason, + payload, + } => { + if event.pubkey != self.admin_pubkey + && *reason != DephyGachaStatusReason::UserRequest + { + tracing::error!( + "User can only use reason UserRequest, skip event: {:?}", + event + ); + } + + let Some(mention) = extract_mention(event) else { + tracing::error!("Machine not mentioned in event, skip event: {:?}", event); + return Ok(()); + }; + + let Ok(machine_pubkey) = PublicKey::parse(mention) else { + tracing::error!("Failed to parse machine pubkey, skip event: {:?}", mention); + return Ok(()); + }; + + let Some(machine) = self.machines.get(&machine_pubkey) else { + tracing::error!("Machine not controlled by us, skip event: {:?}", mention); + return Ok(()); + }; + + if machine.status == *to_status { + tracing::error!( + "Machine already in requested status, skip event: {:?}", + event + ); + return Ok(()); + } + + if *to_status == DephyGachaStatus::Available { + if *reason == DephyGachaStatusReason::UserRequest { + tracing::error!( + "User cannot manually stop machine, skip event: {:?}", + event + ); + return Ok(()); + } + + if let Some(ref original_request) = machine.initial_request { + if original_request != initial_request { + tracing::error!( + "Machine already in working status with different request, skip event: {:?}", + event + ); + return Ok(()); + } + } + } + + let Ok(parsed_payload) = + serde_json::from_str::(payload) + else { + tracing::error!("Failed to parse payload, skip event: {:?}", payload); + return Ok(()); + }; + + if let Err(e) = dephy_balance_payment_sdk::pay( + &self.solana_rpc_url, + &self.solana_keypair_path, + &parsed_payload.user, + PAY_AMOUNT, + &parsed_payload.recover_info, + ) + .await + { + tracing::error!("Failed to pay, error: {:?} skip event: {:?}", e, event); + return Ok(()); + }; + + self.client + .send_event(mention, &DephyGachaMessage::Status { + status: *to_status, + reason: *reason, + initial_request: event.id, + payload: serde_json::to_string(&DephyGachaMessageStatusPayload { + user: parsed_payload.user.clone(), + nonce: parsed_payload.nonce, + recover_info: parsed_payload.recover_info.clone(), + })?, + }) + .await?; + + // TODO: Should check this by machine api + if *to_status == DephyGachaStatus::Working { + let client = self.client.clone(); + let mention = mention.to_string(); + let event_id = event.id; + tokio::spawn(async move { + tokio::time::sleep(std::time::Duration::from_secs(10)).await; + client + .send_event(&mention, &DephyGachaMessage::Status { + status: DephyGachaStatus::Available, + reason: DephyGachaStatusReason::UserBehaviour, + initial_request: event_id, + payload: serde_json::to_string(&DephyGachaMessageStatusPayload { + user: parsed_payload.user.clone(), + nonce: parsed_payload.nonce, + recover_info: parsed_payload.recover_info, + }) + .unwrap(), + }) + .await + .unwrap(); + }); + } + } + DephyGachaMessage::Status { .. } => self.update_machine(event).await?, + } + Ok(()) + } +} diff --git a/dephy-vending_machine-examples/examples/gacha-controller/src/node/mod.rs b/dephy-vending_machine-examples/examples/gacha-controller/src/node/mod.rs new file mode 100644 index 0000000..e4ecd47 --- /dev/null +++ b/dephy-vending_machine-examples/examples/gacha-controller/src/node/mod.rs @@ -0,0 +1,3 @@ +mod message_handler; + +pub use message_handler::MessageHandler; diff --git a/dephy-vending_machine-examples/examples/gacha-controller/src/relay_client.rs b/dephy-vending_machine-examples/examples/gacha-controller/src/relay_client.rs new file mode 100644 index 0000000..de4b2b8 --- /dev/null +++ b/dephy-vending_machine-examples/examples/gacha-controller/src/relay_client.rs @@ -0,0 +1,182 @@ +use nostr::Event; +use nostr::EventBuilder; +use nostr::Filter; +use nostr::Keys; +use nostr::PublicKey; +use nostr::SingleLetterTag; +use nostr::SubscriptionId; +use nostr::Tag; +use nostr::Timestamp; +use nostr_sdk::prelude::ReqExitPolicy; +use nostr_sdk::Client; +use nostr_sdk::RelayPoolNotification; +use nostr_sdk::RelayStatus; +use nostr_sdk::SubscribeAutoCloseOptions; +use tokio::sync::broadcast::Receiver; + +const EVENT_KIND: nostr::Kind = nostr::Kind::Custom(1573); +const MENTION_TAG: SingleLetterTag = SingleLetterTag::lowercase(nostr::Alphabet::P); +const SESSION_TAG: SingleLetterTag = SingleLetterTag::lowercase(nostr::Alphabet::S); + +#[derive(Debug, thiserror::Error)] +#[non_exhaustive] +pub enum Error { + #[error("Nostr client error: {0}")] + NostrClient(#[from] nostr_sdk::client::Error), + #[error("Serde json error: {0}")] + SerdeJson(#[from] serde_json::Error), + #[error("Send event error: {0}")] + SendEvent(String), +} + +#[derive(Clone)] +pub struct RelayClient { + client: Client, + session: String, +} + +impl RelayClient { + pub async fn new( + nostr_relay: &str, + keys: &Keys, + session: &str, + max_notification_size: usize, + ) -> Result { + let client_opts = + nostr_sdk::Options::default().notification_channel_size(max_notification_size); + + let client = Client::builder() + .signer(keys.clone()) + .opts(client_opts) + .build(); + + client.add_relay(nostr_relay).await?; + client.connect().await; + + Ok(Self { + client, + session: session.to_string(), + }) + } + + pub async fn run_relay_checker(self, interval: std::time::Duration) { + loop { + tokio::time::sleep(interval).await; + + let connected_relay_count = self + .client + .relays() + .await + .values() + .filter(|relay| relay.status() == RelayStatus::Connected) + .count(); + + if connected_relay_count == 0 { + panic!("Lost connection to relay"); + } + } + } + + pub fn notifications(&self) -> Receiver { + self.client.notifications() + } + + pub async fn subscribe_last_event( + &self, + until: Timestamp, + author: Option<&PublicKey>, + mention: &PublicKey, + ) -> Result { + let mut filter = Filter::new(); + + filter = filter + .kind(EVENT_KIND) + .until(until) + .custom_tag(SESSION_TAG, [&self.session]) + .custom_tag(MENTION_TAG, [mention.to_hex()]) + .limit(1); + + if let Some(author) = author { + filter = filter.author(*author) + } + + let close_option = + SubscribeAutoCloseOptions::default().exit_policy(ReqExitPolicy::ExitOnEOSE); + let output = self + .client + .subscribe(vec![filter], Some(close_option)) + .await?; + + Ok(output.id().clone()) + } + + pub async fn subscribe( + &self, + since: Timestamp, + mentions: I, + ) -> Result + where + I: IntoIterator, + { + let filter = Filter::new() + .kind(EVENT_KIND) + .since(since) + .custom_tag(SESSION_TAG, [&self.session]) + .custom_tag(MENTION_TAG, mentions.into_iter().map(|pk| pk.to_hex())); + + let output = self.client.subscribe(vec![filter], None).await?; + + Ok(output.id().clone()) + } + + pub async fn subscribe_all(&self, since: Option) -> Result { + let mut filter = Filter::new() + .kind(EVENT_KIND) + .custom_tag(SESSION_TAG, [&self.session]); + + if let Some(since) = since { + filter = filter.since(since); + } + + let output = self.client.subscribe(vec![filter], None).await?; + + Ok(output.id().clone()) + } + + pub async fn send_event(&self, to: &str, message: &M) -> Result<(), Error> + where M: serde::Serialize + std::fmt::Debug { + let content = serde_json::to_string(message)?; + + let event_builder = EventBuilder::new(EVENT_KIND, content).tags([ + Tag::parse(["s".to_string(), self.session.clone()]).unwrap(), + Tag::parse(["p".to_string(), to.to_string()]).unwrap(), + ]); + + let res = self.client.send_event_builder(event_builder).await?; + + if !res.failed.is_empty() { + for (relay_url, err) in res.failed.iter() { + tracing::error!("failed to send event to {} err: {:?}", relay_url, err); + } + return Err(Error::SendEvent(format!( + "Failed to send event {message:?} to relay" + ))); + } + + Ok(()) + } +} + +pub fn extract_mention(event: &Event) -> Option<&str> { + event + .tags + .iter() + .filter_map(|tag| { + if tag.single_letter_tag() == Some(MENTION_TAG) { + tag.content() + } else { + None + } + }) + .next() +} diff --git a/dephy-vending_machine-examples/keypairs/bot.demo.json b/dephy-vending_machine-examples/keypairs/bot.demo.json new file mode 100644 index 0000000..33396d4 --- /dev/null +++ b/dephy-vending_machine-examples/keypairs/bot.demo.json @@ -0,0 +1 @@ +[44,207,158,7,241,71,195,163,219,208,30,139,23,10,103,142,141,128,178,105,198,92,182,10,106,135,254,83,66,166,67,43,130,164,191,76,199,232,128,86,121,179,95,252,112,113,109,20,72,95,231,238,212,22,54,11,184,213,97,70,103,19,106,226] diff --git a/dephy-vending_machine-examples/keypairs/user.demo.json b/dephy-vending_machine-examples/keypairs/user.demo.json new file mode 100644 index 0000000..cbafc5b --- /dev/null +++ b/dephy-vending_machine-examples/keypairs/user.demo.json @@ -0,0 +1 @@ +[217,84,19,12,238,222,160,44,140,57,205,228,164,72,186,127,152,217,218,235,201,22,54,234,187,138,129,167,83,9,87,177,196,67,202,217,204,23,61,11,118,126,77,248,143,227,5,39,3,26,126,6,67,228,190,144,149,109,173,251,108,74,221,200] diff --git a/dephy-vending_machine-examples/rustfmt.toml b/dephy-vending_machine-examples/rustfmt.toml new file mode 100644 index 0000000..cb1a6f9 --- /dev/null +++ b/dephy-vending_machine-examples/rustfmt.toml @@ -0,0 +1,13 @@ +edition = "2021" +unstable_features = true +tab_spaces = 4 +hard_tabs = false +reorder_imports = true +format_code_in_doc_comments = true +wrap_comments = false +format_strings = false +imports_granularity = "Item" +group_imports = "StdExternalCrate" +where_single_line = true +trailing_comma = "Vertical" +overflow_delimited_expr = true diff --git a/dephy-vending_machine-examples/taplo.toml b/dephy-vending_machine-examples/taplo.toml new file mode 100644 index 0000000..f028e77 --- /dev/null +++ b/dephy-vending_machine-examples/taplo.toml @@ -0,0 +1,36 @@ +## https://taplo.tamasfe.dev/configuration/#configuration-file + +include = ["**/Cargo.toml"] + +[formatting] +# Align consecutive entries vertically. +align_entries = false +# Append trailing commas for multi-line arrays. +array_trailing_comma = true +# Expand arrays to multiple lines that exceed the maximum column width. +array_auto_expand = true +# Collapse arrays that don't exceed the maximum column width and don't contain comments. +array_auto_collapse = false +# Omit white space padding from single-line arrays +compact_arrays = true +# Omit white space padding from the start and end of inline tables. +compact_inline_tables = false +# Maximum column width in characters, affects array expansion and collapse, this doesn't take whitespace into account. +# Note that this is not set in stone, and works on a best-effort basis. +column_width = 500 +# Indent based on tables and arrays of tables and their subtables, subtables out of order are not indented. +indent_tables = false +# The substring that is used for indentation, should be tabs or spaces (but technically can be anything). +indent_string = ' ' +# Add trailing newline at the end of the file if not present. +trailing_newline = true +# Alphabetically reorder keys that are not separated by empty lines. +reorder_keys = false +# Maximum amount of allowed consecutive blank lines. This does not affect the whitespace at the end of the document, as it is always stripped. +allowed_blank_lines = 1 +# Use CRLF for line endings. +crlf = false + +[[rule]] +keys = ["dependencies", "dev-dependencies", "build-dependencies", "workspace.dependencies"] +formatting = { reorder_keys = true } diff --git a/dephy-vending_machine-examples/typos.toml b/dephy-vending_machine-examples/typos.toml new file mode 100644 index 0000000..2631f4c --- /dev/null +++ b/dephy-vending_machine-examples/typos.toml @@ -0,0 +1,3 @@ +[default.extend-words] +# skip `Ue` +Ue = "Ue"