diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 00000000..c91c3f38 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,2 @@ +[net] +git-fetch-with-cli = true diff --git a/.github/actions/install-solc/action.yml b/.github/actions/install-solc/action.yml new file mode 100644 index 00000000..eb5f8301 --- /dev/null +++ b/.github/actions/install-solc/action.yml @@ -0,0 +1,23 @@ +--- +name: 'Install Solc' +description: 'Installs the Solc compiler.' +inputs: + solc-version: + description: 'The latest version of solc.' + required: false + default: '0.8.26' +runs: + using: "composite" + steps: + - name: Install solc compiler + shell: bash + run: | + if ! solc --version &> /dev/null || + [[ $(solc --version | grep -oP '(\d+\.\d+\.\d+)' | head -n 1) \ + != ${{ inputs.solc-version }} ]]; then + cargo install solc-select --force + solc-select install ${{ inputs.solc-version }} + solc-select use ${{ inputs.solc-version }} + else + echo "solc is already installed." + fi diff --git a/.github/actions/prepare-rust-env/action.yml b/.github/actions/prepare-rust-env/action.yml new file mode 100644 index 00000000..089dce21 --- /dev/null +++ b/.github/actions/prepare-rust-env/action.yml @@ -0,0 +1,29 @@ +--- +name: 'Prepare Rust environment' +description: > + Installs Rust toolchain, authenticates with SSH (in order to access Github private repos) +inputs: + poseidon-gadget-private-key: + description: 'SSH private key that corresponds to the deploy key in poseidon2-gadget repository' + required: true + zkos-circuits-private-key: + description: 'SSH private key that corresponds to the deploy key in zkos-circuits repository' + required: true + +runs: + using: composite + steps: + - uses: webfactory/ssh-agent@v0.9.0 + with: + ssh-private-key: | + ${{ inputs.poseidon-gadget-private-key }} + ${{ inputs.zkos-circuits-private-key }} + + - name: Install Rust toolchain + uses: Cardinal-Cryptography/github-actions/install-rust-toolchain@v7 + with: + channel: nightly + + - name: Install sccache + shell: bash + run: scripts/install-sccache diff --git a/.github/actions/shielder-relayer/build-and-push/action.yml b/.github/actions/shielder-relayer/build-and-push/action.yml new file mode 100644 index 00000000..f71b92a7 --- /dev/null +++ b/.github/actions/shielder-relayer/build-and-push/action.yml @@ -0,0 +1,56 @@ +--- +name: Build and push docker image + +inputs: + aws-mainnet-ecr-access-key: + required: true + aws-mainnet-ecr-access-key-id: + required: true + ecr-private-host: + description: ECR private host + required: true + +outputs: + image_tag: + description: Tag of the pushed image + value: ${{ steps.outputs.outputs.image_tag }} + +runs: + using: composite + steps: + - name: Call action get-ref-properties + id: get-ref-properties + uses: Cardinal-Cryptography/github-actions/get-ref-properties@v6 + + - name: DOCKER | Login to private Amazon ECR + id: login-private-ecr + uses: docker/login-action@v2 + with: + registry: ${{ inputs.ecr-private-host }} + username: ${{ inputs.aws-mainnet-ecr-access-key-id }} + password: ${{ inputs.aws-mainnet-ecr-access-key }} + env: + AWS_REGION: us-east-1 + + - name: DOCKER | Docker Buildx + id: buildx + uses: docker/setup-buildx-action@v2 + with: + version: v0.9.1 + + - name: DOCKER | Build and push latest docker image + id: build-image + uses: docker/build-push-action@v3 + with: + context: . + builder: ${{ steps.buildx.outputs.name }} + file: ./crates/shielder-relayer/docker/Dockerfile + push: true + tags: "${{ inputs.ecr-private-host }}/shielder-relayer:\ + ${{ steps.get-ref-properties.outputs.sha }}" + + - name: OUTPUTS | Set output with docker image + id: outputs + shell: bash + run: | + echo "image_tag=${{ steps.get-ref-properties.outputs.sha }}" >> $GITHUB_OUTPUT diff --git a/.github/actions/shielder-relayer/deploy/action.yml b/.github/actions/shielder-relayer/deploy/action.yml new file mode 100644 index 00000000..74d0c1f1 --- /dev/null +++ b/.github/actions/shielder-relayer/deploy/action.yml @@ -0,0 +1,66 @@ +--- +name: Deploy docker image + +inputs: + image-tag: + description: Tag of the docker image to be deployed + required: true + autocommit-author: + description: Commit author + required: true + autocommit-email: + description: Commit author's mail + required: true + github-token: + description: Github token + required: true + ecr-private-host: + description: ECR private host + required: true + kustomize-version: + description: Kustomize version + required: true + environment: + type: choice + options: + - testnet-dev + - testnet + - mainnet + required: true + +runs: + using: composite + steps: + - name: GIT | Checkout aleph-apps repo + uses: actions/checkout@v4 + with: + repository: Cardinal-Cryptography/aleph-apps + token: ${{ inputs.github-token }} + path: "aleph-apps" + ref: main + + - name: KUSTOMIZE | Init kustomize + uses: imranismail/setup-kustomize@v2 + with: + kustomize-version: ${{ inputs.kustomize-version }} + + - name: KUSTOMIZE | Update docker image tag + shell: bash + env: + DEPLOY_IMAGE: ${{ inputs.ecr-private-host }}/shielder-relayer:${{ inputs.image-tag }} + run: | + cd aleph-apps/shielder-relayer/overlays/${{ inputs.environment }}/eu-central-1 + kustomize edit set image "shielder-relayer-image-placeholder=${{ env.DEPLOY_IMAGE }}" + + - name: GIT | Commit changes to aleph-apps repository + uses: EndBug/add-and-commit@v9.1.4 + env: + GITHUB_TOKEN: ${{ inputs.github-token }} + with: + author_name: ${{ inputs.autocommit-author }} + author_email: ${{ inputs.autocommit-email }} + message: > + Updating shielder-relayer ${{ inputs.environment }} + docker image tag: ${{ inputs.image-tag }} + add: "*.yaml" + cwd: 'aleph-apps' diff --git a/.github/workflows/_build-contracts.yml b/.github/workflows/_build-contracts.yml new file mode 100644 index 00000000..2630fcd6 --- /dev/null +++ b/.github/workflows/_build-contracts.yml @@ -0,0 +1,60 @@ +--- +name: Generate, compile and lint contracts + +on: + workflow_call: + workflow_dispatch: + +jobs: + main: + name: Generate, compile and lint contracts + runs-on: [self-hosted, Linux, X64, large] + #runs-on: ubuntu-20.04 + timeout-minutes: 10 + + steps: + - name: Checkout source code + uses: actions/checkout@v4 + + - name: Prepare Rust env + uses: ./.github/actions/prepare-rust-env + with: + poseidon-gadget-private-key: ${{ secrets.SSH_PRIVATE_KEY }} + zkos-circuits-private-key: ${{ secrets.ZKOS_CIRCUITS_SSH_PRIVATE_KEY }} + + - name: Setup node + uses: asdf-vm/actions/install@v3 + + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1.2.0 + with: + cache-key: custom-seed-coverage-${{ github.ref_name }} + cache-restore-keys: |- + contract-suite + version: nightly-31dd1f77fd9156d09836486d97963cec7f555343 + + - name: Lint contracts code (excluding generated code) + shell: bash + run: make deps && make lint-contracts + + - name: Regenerate verifier and Poseidon contracts and ensure that they are up-to-date + run: | + make generate-verifier-contracts && make generate-poseidon-contracts && \ + git diff --exit-code -- contracts/ + + - name: Compile eth contracts + run: make compile-contracts + + - name: Upload generated contracts to artifacts + uses: actions/upload-artifact@v4 + with: + name: generated-contracts + path: contracts + retention-days: 1 + + - name: Upload bytecode and ABI to artifacts + uses: actions/upload-artifact@v4 + with: + name: contract-artifacts + path: artifacts + retention-days: 1 diff --git a/.github/workflows/_build-wasm-packages.yml b/.github/workflows/_build-wasm-packages.yml new file mode 100644 index 00000000..c62d9e89 --- /dev/null +++ b/.github/workflows/_build-wasm-packages.yml @@ -0,0 +1,35 @@ +--- +name: Build wasm packages + +on: + workflow_call: + workflow_dispatch: + +jobs: + main: + name: Build wasm packages + runs-on: [self-hosted, Linux, X64, large] + timeout-minutes: 10 + + steps: + - name: Checkout source code + uses: actions/checkout@v4 + + - name: Prepare Rust env + uses: ./.github/actions/prepare-rust-env + with: + poseidon-gadget-private-key: ${{ secrets.SSH_PRIVATE_KEY }} + zkos-circuits-private-key: ${{ secrets.ZKOS_CIRCUITS_SSH_PRIVATE_KEY }} + + - name: Install wasm-pack + run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh + + - name: Build shielder-wasm + run: cd crates/shielder-wasm && make all + + - name: Upload generated wasm to artifacts + uses: actions/upload-artifact@v4 + with: + name: crates-shielder-wasm-pkg + path: crates/shielder-wasm/pkg + retention-days: 1 diff --git a/.github/workflows/_check-vars-and-secrets.yml b/.github/workflows/_check-vars-and-secrets.yml new file mode 100644 index 00000000..3f7050f4 --- /dev/null +++ b/.github/workflows/_check-vars-and-secrets.yml @@ -0,0 +1,55 @@ +--- +# This workflow checks if vars and secrets are present and fails if one is empty. +# It should be included as a first step in all the workflows. +name: Check vars and secrets +on: + workflow_call: + +jobs: + main: + name: Check available vars and secrets + runs-on: ubuntu-20.04 + steps: + - name: Check vars + run: | + if [[ \ + -z '${{ vars.SHIELDER_CONTRACT_ADDRESS }}' || \ + -z '${{ vars.KUSTOMIZE_VERSION }}' || \ + -z '${{ vars.CI_TESTNET_ALICE_PUBLIC_KEY }} }}' || \ + -z '${{ vars.CI_TESTNET_BOB_PUBLIC_KEY }} }}' || \ + -z '${{ vars.CI_TESTNET_CHARLIE_PUBLIC_KEY }} }}' || \ + -z '${{ vars.CI_TESTNET_RELAYER_SIGNER_ADDRESSES }} }}' || \ + -z '${{ vars.CI_TESTNET_FEE_DESTINATION }} }}' + ]]; then + echo '!!! Some repository variables are either missing or empty.' + echo '!!! Please check either repository or organization settings.' + exit 1 + fi + + - name: Check secrets + run: | + if [[ \ + -z '${{ secrets.ZKOS_CIRCUITS_SSH_PRIVATE_KEY }}' || \ + -z '${{ secrets.SSH_PRIVATE_KEY }}' || \ + -z '${{ secrets.VERCEL_ORG_ID }}' || \ + -z '${{ secrets.VERCEL_PROJECT_ID }}' || \ + -z '${{ secrets.VERCEL_TOKEN }}' || \ + -z '${{ secrets.AWS_MAINNET_ECR_ACCESS_KEY_ID }}' || \ + -z '${{ secrets.AWS_MAINNET_ECR_ACCESS_KEY }}' || \ + -z '${{ secrets.ECR_PRIVATE_HOST }}' || \ + -z '${{ secrets.AUTOCOMMIT_AUTHOR }}' || \ + -z '${{ secrets.AUTOCOMMIT_EMAIL }}' || \ + -z '${{ secrets.CI_GH_TOKEN }}' || \ + -z '${{ secrets.SLACK_WEBHOOK_ZKOS }}' || \ + -z '${{ secrets.CI_TESTNET_DEPLOYER_PRIVATE_KEY }}' || \ + -z '${{ secrets.CI_TESTNET_ALICE_PRIVATE_KEY }}' || \ + -z '${{ secrets.CI_TESTNET_BOB_PRIVATE_KEY }}' || \ + -z '${{ secrets.CI_TESTNET_CHARLIE_PRIVATE_KEY }}' || \ + -z '${{ secrets.CI_TESTNET_FEE_DESTINATION_KEY }}' || \ + -z '${{ secrets.CI_TESTNET_RELAYER_SIGNING_KEYS }}' || \ + -z '${{ secrets.NPM_PUBLISHING_KEY }}' + ]]; then + echo '!!! Some repository secrets are either missing or empty.' + echo '!!! Please check either repository or organization settings.' + exit 1 + fi diff --git a/.github/workflows/_deploy-contracts.yml b/.github/workflows/_deploy-contracts.yml new file mode 100644 index 00000000..f7c407bf --- /dev/null +++ b/.github/workflows/_deploy-contracts.yml @@ -0,0 +1,51 @@ +--- +name: Deploy contracts + +on: + workflow_call: + workflow_dispatch: + +jobs: + main: + name: Deploy contracts to the anvil network + runs-on: ubuntu-22.04 + timeout-minutes: 10 + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup node + uses: asdf-vm/actions/install@v3 + + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1.2.0 + with: + cache-key: custom-seed-coverage-${{ github.ref_name }} + cache-restore-keys: |- + contract-suite + version: nightly-31dd1f77fd9156d09836486d97963cec7f555343 + + - name: Run anvil node in background + shell: bash + run: make anvil & + + - name: Install dependencies + shell: bash + run: make deps + + - name: Download generated contracts from artifacts + uses: actions/download-artifact@v4 + with: + name: generated-contracts + path: contracts + + - name: Download compiled contracts from artifacts + uses: actions/download-artifact@v4 + with: + name: contract-artifacts + path: artifacts + + - name: deploy eth contracts + shell: bash + run: NETWORK=anvil make deploy-contracts diff --git a/.github/workflows/_rust-crates-checks.yml b/.github/workflows/_rust-crates-checks.yml new file mode 100644 index 00000000..a905b478 --- /dev/null +++ b/.github/workflows/_rust-crates-checks.yml @@ -0,0 +1,110 @@ +--- +name: Run linter and tests for all Rust crates + +on: + workflow_call: + workflow_dispatch: + +jobs: + # Run formatter and linter for all crates, and unit tests for all simple crates, that, + # in particular, do not require anvil node to be running. + # For shielder-circuit crate, we run tests and build the binary for measuring circuits. + rust-checks-and-unit-tests: + name: Run lints and tests + runs-on: [self-hosted, Linux, X64, large] + timeout-minutes: 60 + env: + RUSTC_WRAPPER: sccache + steps: + - name: Checkout source code + uses: actions/checkout@v4 + + - name: Download generated contracts from artifacts + uses: actions/download-artifact@v4 + with: + name: generated-contracts + path: contracts + + - name: Download compiled contracts from artifacts + uses: actions/download-artifact@v4 + with: + name: contract-artifacts + path: artifacts + + - name: Prepare Rust env + uses: ./.github/actions/prepare-rust-env + with: + poseidon-gadget-private-key: ${{ secrets.SSH_PRIVATE_KEY }} + zkos-circuits-private-key: ${{ secrets.ZKOS_CIRCUITS_SSH_PRIVATE_KEY }} + + # NOTE: integration tests use vanilla solc compiler for compiling Solidity + - name: Install solc compiler + uses: ./.github/actions/install-solc + with: + solc-version: 0.8.26 + + - name: Run linter + run: | + make lint-rust + make format-rust + + - name: Run tests for Shielder Rust SDK + run: cargo test --release -p shielder-rust-sdk --all-features + + - name: Run tests for halo2-verifier + run: cd crates/halo2-verifier && make test + + - name: Run tests for shielder-cli + run: cd crates/shielder-cli && make test + + - name: Run tests for shielder-wasm + run: cd crates/shielder-wasm && make test + + - name: Run integration tests + run: make deps && cargo test --release -p integration-tests + + # Run heavy tests for shielder-relayer and e2e tooling tests. + full-testing: + name: Run heavy tests + runs-on: [self-hosted, Linux, X64, large] + timeout-minutes: 60 + env: + RUSTC_WRAPPER: sccache + steps: + - name: Checkout source code + uses: actions/checkout@v4 + + - name: Download generated contracts from artifacts + uses: actions/download-artifact@v4 + with: + name: generated-contracts + path: contracts + + - name: Download compiled contracts from artifacts + uses: actions/download-artifact@v4 + with: + name: contract-artifacts + path: artifacts + + - name: Prepare Rust env + uses: ./.github/actions/prepare-rust-env + with: + poseidon-gadget-private-key: ${{ secrets.SSH_PRIVATE_KEY }} + zkos-circuits-private-key: ${{ secrets.ZKOS_CIRCUITS_SSH_PRIVATE_KEY }} + + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1.2.0 + with: + cache-key: custom-seed-coverage-${{ github.ref_name }} + cache-restore-keys: |- + contract-suite + version: nightly-31dd1f77fd9156d09836486d97963cec7f555343 + + - name: Run tests for shielder-relayer + run: make deps && cd crates/shielder-relayer && BUILD=client make test + + - name: Run e2e tooling tests + run: | + NO_FORMATTING=true ./tooling-e2e-tests/full_scenario.sh + NO_FORMATTING=true ./tooling-e2e-tests/recovery_scenario.sh + NO_FORMATTING=true ./tooling-e2e-tests/many_actors.sh diff --git a/.github/workflows/_ts-checks.yml b/.github/workflows/_ts-checks.yml new file mode 100644 index 00000000..f9e8a19f --- /dev/null +++ b/.github/workflows/_ts-checks.yml @@ -0,0 +1,69 @@ +--- +name: Run linter and tests for all Typescript modules + +on: + workflow_call: + workflow_dispatch: + +env: + PLASMO_PUBLIC_SHIELDER_CONTRACT_ADDRESS: ${{ vars.SHIELDER_CONTRACT_ADDRESS }} + +jobs: + main: + name: Run lints and tests + runs-on: [self-hosted, Linux, X64, small] + timeout-minutes: 10 + + steps: + - name: Display variables + run: | + echo "PLASMO_PUBLIC_SHIELDER_CONTRACT_ADDRESS: \ + ${{ env.PLASMO_PUBLIC_SHIELDER_CONTRACT_ADDRESS }}" + + - uses: webfactory/ssh-agent@v0.9.0 + with: + ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }} + + - name: Checkout source code + uses: actions/checkout@v4 + + - name: Cache pnpm modules + uses: actions/cache@v4 + with: + path: ~/.pnpm-store + key: ${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}- + + - name: Download compiled contracts from artifacts + uses: actions/download-artifact@v4 + with: + name: contract-artifacts + path: artifacts + + - name: Download generated wasm from artifacts + uses: actions/download-artifact@v4 + with: + name: crates-shielder-wasm-pkg + path: crates/shielder-wasm/pkg + + - name: Install Node.js + uses: actions/setup-node@v4 + with: + node-version: 18 + + - uses: pnpm/action-setup@v4 + with: + version: latest + + - name: Install dependencies (shielder-sdk) + run: pnpm install --frozen-lockfile + working-directory: ts/shielder-sdk + + - name: Build shielder-sdk + run: pnpm build + working-directory: ts/shielder-sdk + + - name: Run lint checks (shielder-sdk) + run: pnpm lint + working-directory: ts/shielder-sdk diff --git a/.github/workflows/_ts-sdk-playwright-tests.yml b/.github/workflows/_ts-sdk-playwright-tests.yml new file mode 100644 index 00000000..61a5c628 --- /dev/null +++ b/.github/workflows/_ts-sdk-playwright-tests.yml @@ -0,0 +1,257 @@ +--- +name: Run sharded Playwright tests for shielder-sdk + +on: + workflow_call: + workflow_dispatch: + +jobs: + build-rust-binary: + name: Build Rust binary + runs-on: ubuntu-22.04 + timeout-minutes: 10 + env: + RUSTC_WRAPPER: sccache + steps: + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Checkout source code + uses: actions/checkout@v4 + + - name: Prepare Rust env + uses: ./.github/actions/prepare-rust-env + with: + poseidon-gadget-private-key: ${{ secrets.SSH_PRIVATE_KEY }} + zkos-circuits-private-key: ${{ secrets.ZKOS_CIRCUITS_SSH_PRIVATE_KEY }} + + - name: Build Rust binary + run: cargo build --manifest-path crates/test-ts-conversions/Cargo.toml + + - name: Build relayer + run: cd crates/shielder-relayer && make build + + - name: DOCKER | Build and push latest docker image + id: build-image + uses: docker/build-push-action@v3 + with: + context: . + builder: ${{ steps.buildx.outputs.name }} + file: ./crates/shielder-relayer/docker/Dockerfile.client + tags: shielder-relayer + outputs: type=docker,dest=/tmp/shielder-relayer.tar + + - name: Upload binary to artifacts + uses: actions/upload-artifact@v4 + with: + name: test-ts-conversions-binary + path: target/debug/test-ts-conversions + retention-days: 1 + + - name: Upload docker image to artifacts + uses: actions/upload-artifact@v4 + with: + name: shielder-relayer-docker-image + path: /tmp/shielder-relayer.tar + retention-days: 1 + + ts-sdk-playwright-tests: + name: Run shielder-sdk Playwright tests + runs-on: ubuntu-22.04 + needs: [build-rust-binary] + timeout-minutes: 10 + strategy: + fail-fast: false + matrix: + # When increasing parallelism, make it so at least 2 tests are run per worker + # by having `shardTotal <= total_number_of_tests / 2`. + # This way repeated usage of WASM wrappers within worker is tested as a side effect. + shardIndex: [1] + shardTotal: [1] + threads: [st, mt] + steps: + - uses: webfactory/ssh-agent@v0.9.0 + with: + ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }} + + - name: Checkout source code + uses: actions/checkout@v4 + + - name: Cache pnpm modules + uses: actions/cache@v4 + with: + path: ~/.pnpm-store + key: ${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}- + + - name: Install Node.js + uses: actions/setup-node@v4 + with: + node-version: 18 + + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1.2.0 + with: + cache-key: custom-seed-coverage-${{ github.ref_name }} + cache-restore-keys: |- + contract-suite + version: nightly-31dd1f77fd9156d09836486d97963cec7f555343 + + - name: Run anvil node in background + shell: bash + run: make anvil & + + - name: Install dependencies + shell: bash + run: make deps + + - name: Download generated contracts from artifacts + uses: actions/download-artifact@v4 + with: + name: generated-contracts + path: contracts + + - name: Download compiled contracts from artifacts + uses: actions/download-artifact@v4 + with: + name: contract-artifacts + path: artifacts + + - name: Deploy eth contracts + shell: bash + run: | + NETWORK=anvil make deploy-contracts + SHIELDER_CONTRACT_ADDRESS=$( + NETWORK=anvil make deploy-contracts \ + | grep 'Shielder deployed at:' | awk '{print $NF}') + echo "SHIELDER_CONTRACT_ADDRESS=${SHIELDER_CONTRACT_ADDRESS}" >> $GITHUB_ENV + + - name: Download generated wasm from artifacts + uses: actions/download-artifact@v4 + with: + name: crates-shielder-wasm-pkg + path: crates/shielder-wasm/pkg + + - name: Download binary from artifacts + uses: actions/download-artifact@v4 + with: + name: test-ts-conversions-binary + path: target/debug + + - name: Download relayer image from artifacts + uses: actions/download-artifact@v4 + with: + name: shielder-relayer-docker-image + path: /tmp + + - name: Load relayer image + run: docker load --input /tmp/shielder-relayer.tar + + - name: Run shielder-relayer + run: | + source ../../tooling-e2e-tests/local_env.sh + DOCKER_USER="$(id -u):$(id -g)" \ + RELAYER_CONTAINER_NAME=shielder-relayer \ + RELAYER_DOCKER_IMAGE=shielder-relayer \ + ./run-relayer.sh& + working-directory: crates/shielder-relayer + + - name: Executable permissions + run: chmod +x target/debug/test-ts-conversions + + - uses: pnpm/action-setup@v4 + with: + version: latest + + - name: Install dependencies (shielder-sdk) + run: pnpm install --frozen-lockfile + working-directory: ts/shielder-sdk + + - name: Build shielder-sdk + run: pnpm build + working-directory: ts/shielder-sdk + + - name: Install dependencies (shielder-sdk-tests) + run: pnpm install --frozen-lockfile + working-directory: ts/shielder-sdk-tests + + - name: Install Playwright dependencies (shielder-sdk-tests) + run: pnpm postinstall + working-directory: ts/shielder-sdk-tests + + - name: Build shielder-sdk-tests + run: pnpm build + working-directory: ts/shielder-sdk-tests + + - name: Run tests (shielder-sdk-tests) + run: | + if [[ ${{ matrix.threads }} == "st" ]]; then + CONFIG="playwright.singlethreaded.config.mjs" + else + CONFIG="playwright.multithreaded.config.mjs" + fi + source ../../tooling-e2e-tests/local_env.sh + RELAYER_SIGNER_ADDRESSES="$RELAYER_SIGNER_ADDRESSES" \ + pnpm playwright test --config $CONFIG \ + --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }} + working-directory: ts/shielder-sdk-tests + + - name: Upload blob report to GitHub Actions Artifacts + if: ${{ !cancelled() }} + uses: actions/upload-artifact@v4 + with: + name: "ts-sdk-tests-shard-report\ + -${{ matrix.threads }}\ + -${{ matrix.shardIndex }}\ + -${{ matrix.shardTotal }}" + path: ts/shielder-sdk-tests/blob-report + retention-days: 1 + + merge-reports: + if: ${{ !cancelled() }} + needs: [ts-sdk-playwright-tests] + strategy: + fail-fast: false + matrix: + threads: [mt] + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: 18 + - name: Install dependencies + run: npm ci + + - name: Download blob reports from GitHub Actions Artifacts + uses: actions/download-artifact@v4 + with: + path: all-blob-reports + pattern: ts-sdk-tests-shard-report-${{ matrix.threads }}-* + merge-multiple: true + + - name: Print merged report + run: npx playwright merge-reports --reporter list ./all-blob-reports + + - name: Store merged report in HTML + run: npx playwright merge-reports --reporter html ./all-blob-reports + + - name: Upload HTML report + uses: actions/upload-artifact@v4 + with: + name: ts-sdk-tests-report-${{ matrix.threads }}-attempt-${{ github.run_attempt }} + path: playwright-report + retention-days: 14 + + clean-rust-artifact: + name: Clean rust artifacts + runs-on: ubuntu-22.04 + if: ${{ always() }} + needs: [ts-sdk-playwright-tests] + steps: + - uses: geekyeggo/delete-artifact@v5 + with: + name: | + test-ts-conversions-binary + shielder-relayer-docker-image diff --git a/.github/workflows/manual-browser-extension-deployment.yml b/.github/workflows/manual-browser-extension-deployment.yml new file mode 100644 index 00000000..d930119b --- /dev/null +++ b/.github/workflows/manual-browser-extension-deployment.yml @@ -0,0 +1,99 @@ +--- +name: "Manual browser extension deployment" +on: + workflow_dispatch: + inputs: + deployment_type: + description: "Deployment type" + required: true + default: "preview" + type: choice + options: + - "preview" + - "prod" +env: + VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} + VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }} + PROD_OR_PREVIEW: ${{ inputs.deployment_type == 'prod' && '--prod' || '' }} + NODE_VERSION: 18 + PLASMO_PUBLIC_SHIELDER_CONTRACT_ADDRESS: ${{ vars.SHIELDER_CONTRACT_ADDRESS }} +jobs: + build-contracts: + name: Build contracts + uses: ./.github/workflows/_build-contracts.yml + secrets: inherit + build-wasm-packages: + name: Build wasm packages + uses: ./.github/workflows/_build-wasm-packages.yml + secrets: inherit + build-deploy-browser-extension: + name: Build and deploy browser extension + needs: [build-contracts, build-wasm-packages] + runs-on: ubuntu-22.04 + timeout-minutes: 60 + steps: + - name: Display variables + run: | + echo "PROD_OR_PREVIEW: ${{ env.PROD_OR_PREVIEW }}" + echo "SHIELDER_CONTRACT_ADDRESS: ${{ env.PLASMO_PUBLIC_SHIELDER_CONTRACT_ADDRESS }}" + - name: Checkout code + uses: actions/checkout@v4 + - name: Cache pnpm modules + uses: actions/cache@v4 + with: + path: ~/.pnpm-store + key: ${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}- + - name: Download compiled contracts from artifacts + uses: actions/download-artifact@v4 + with: + name: contract-artifacts + path: artifacts + - name: Download generated wasm from artifacts + uses: actions/download-artifact@v4 + with: + name: crates-shielder-wasm-pkg + path: crates/shielder-wasm/pkg + - name: Use Node.js ${{ env.NODE_VERSION }} + uses: actions/setup-node@v4.0.2 + with: + node-version: ${{ env.NODE_VERSION }} + - name: Setup pnpm + uses: pnpm/action-setup@v4.0.0 + with: + version: latest + - name: Install dependencies (shielder-sdk) + run: pnpm install --frozen-lockfile + working-directory: ts/shielder-sdk + - name: Build shielder-sdk + run: pnpm build + working-directory: ts/shielder-sdk + - name: Install dependencies (browser-extension) + run: pnpm install --frozen-lockfile + working-directory: ts/browser-extension + - name: Build extension (webapp) + run: pnpm build + working-directory: ts/browser-extension + - name: Pull vercel data + run: vercel pull --token=${{ secrets.VERCEL_TOKEN }} + working-directory: ts/browser-extension + - name: Build for vercel + run: vercel build ${{ env.PROD_OR_PREVIEW }} --token=${{ secrets.VERCEL_TOKEN }} + working-directory: ts/browser-extension + - name: Deploy to vercel + run: | + vercel deploy \ + --prebuilt ${{ env.PROD_OR_PREVIEW }} \ + --token=${{ secrets.VERCEL_TOKEN }} > deployment-url.txt + echo "frontend preview deployment:
$(cat deployment-url.txt)" > deployment-url.txt + working-directory: ts/browser-extension + clean-wasm-artifact: + name: Clean wasm artifact + if: ${{ always() }} + needs: [build-wasm-packages, build-deploy-browser-extension] + steps: + - uses: geekyeggo/delete-artifact@v5 + with: + name: | + crates-shielder-wasm-pkg diff --git a/.github/workflows/manual-publish-dev-env.yml b/.github/workflows/manual-publish-dev-env.yml new file mode 100644 index 00000000..6272e25b --- /dev/null +++ b/.github/workflows/manual-publish-dev-env.yml @@ -0,0 +1,125 @@ +--- +name: "Build and deploy development environment" + +on: + workflow_dispatch: + +jobs: + build-and-push-relayer: + name: Build and push shielder-relayer + runs-on: [self-hosted, Linux, X64, medium] + steps: + - name: GIT | Checkout + uses: actions/checkout@v4 + + - name: DOCKER | Build and push + uses: ./.github/actions/shielder-relayer/build-and-push + id: build_shielder_relayer + with: + aws-mainnet-ecr-access-key-id: ${{ secrets.AWS_MAINNET_ECR_ACCESS_KEY_ID }} + aws-mainnet-ecr-access-key: ${{ secrets.AWS_MAINNET_ECR_ACCESS_KEY }} + ecr-private-host: ${{ secrets.ECR_PRIVATE_HOST }} + outputs: + image_tag: ${{ steps.build_shielder_relayer.outputs.image_tag }} + + shielder-sdk: + name: Build and push shielder-sdk + runs-on: [self-hosted, Linux, X64, medium] + steps: + - name: GIT | Checkout + uses: actions/checkout@v4 + + - name: Prepare Rust env + uses: ./.github/actions/prepare-rust-env + with: + poseidon-gadget-private-key: ${{ secrets.SSH_PRIVATE_KEY }} + zkos-circuits-private-key: ${{ secrets.ZKOS_CIRCUITS_SSH_PRIVATE_KEY }} + + - name: Install wasm-pack + run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh + + - name: Install Node.js + uses: actions/setup-node@v4 + with: + node-version: 18 + + - uses: pnpm/action-setup@v4 + with: + version: latest + + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1.2.0 + with: + cache-key: custom-seed-coverage-${{ github.ref_name }} + cache-restore-keys: |- + contract-suite + version: nightly-31dd1f77fd9156d09836486d97963cec7f555343 + + - name: Install deps + run: make deps + + - name: Compile eth contracts + run: make compile-contracts + + - name: Build shielder-wasm + run: make all + working-directory: crates/shielder-wasm + + - name: Install dependencies (shielder-sdk) + run: pnpm install --frozen-lockfile + working-directory: ts/shielder-sdk + + - name: Build shielder-sdk + run: pnpm build + working-directory: ts/shielder-sdk + + - name: Add .npmrc with publish token + run: echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_PUBLISHING_KEY }}" > .npmrc + working-directory: ts/shielder-sdk + + - name: Publish shielder-sdk + run: pnpm publish --access restricted --no-git-checks + working-directory: ts/shielder-sdk + + tooling-dev: + name: Generate developer scripts + runs-on: [self-hosted, Linux, X64, medium] + steps: + - name: GIT | Checkout + uses: actions/checkout@v4 + + - name: Install Node.js + uses: actions/setup-node@v4 + with: + node-version: 18 + + - name: Prepare Rust env + uses: ./.github/actions/prepare-rust-env + with: + poseidon-gadget-private-key: ${{ secrets.SSH_PRIVATE_KEY }} + zkos-circuits-private-key: ${{ secrets.ZKOS_CIRCUITS_SSH_PRIVATE_KEY }} + + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1.2.0 + with: + cache-key: custom-seed-coverage-${{ github.ref_name }} + cache-restore-keys: |- + contract-suite + version: nightly-31dd1f77fd9156d09836486d97963cec7f555343 + + - name: Install deps + run: make deps + + - name: Compile eth contracts + run: make compile-contracts + + - name: Generate developer scripts + run: make generate-tooling-dev + + - name: Upload developer scripts to artifacts + uses: actions/upload-artifact@v4 + with: + name: tooling-dev + path: tooling-dev + include-hidden-files: true + retention-days: 14 diff --git a/.github/workflows/on-pull-request-commit.yml b/.github/workflows/on-pull-request-commit.yml new file mode 100644 index 00000000..c53f1728 --- /dev/null +++ b/.github/workflows/on-pull-request-commit.yml @@ -0,0 +1,68 @@ +--- +name: PR commit + +on: + pull_request: + push: + branches: + - main + workflow_dispatch: + +concurrency: + group: "${{ github.ref }}-${{ github.workflow }}" + cancel-in-progress: true + +jobs: + + check-vars-and-secrets: + name: Check vars and secrets + uses: ./.github/workflows/_check-vars-and-secrets.yml + secrets: inherit + + build-contracts: + name: Generate and compile contracts + needs: [check-vars-and-secrets] + uses: ./.github/workflows/_build-contracts.yml + secrets: inherit + + deploy-contracts: + name: Deploy contracts + needs: [build-contracts] + uses: ./.github/workflows/_deploy-contracts.yml + secrets: inherit + + rust-crates-checks: + name: Rust crates checks + needs: [build-contracts] + uses: ./.github/workflows/_rust-crates-checks.yml + secrets: inherit + + build-wasm-packages: + name: Build wasm packages + needs: [check-vars-and-secrets] + uses: ./.github/workflows/_build-wasm-packages.yml + secrets: inherit + + ts-checks: + name: Typescript modules checks + needs: [build-contracts, build-wasm-packages] + uses: ./.github/workflows/_ts-checks.yml + secrets: inherit + + ts-sdk-playwright-tests: + name: Typescript shielder-sdk Playwright tests + needs: [build-contracts, build-wasm-packages] + uses: ./.github/workflows/_ts-sdk-playwright-tests.yml + secrets: inherit + + clean-wasm-artifact: + name: Clean wasm artifact + runs-on: ubuntu-22.04 + if: ${{ always() }} + # dependencies should include all jobs, which interact with wasm artifact + needs: [build-wasm-packages, ts-checks, ts-sdk-playwright-tests] + steps: + - uses: geekyeggo/delete-artifact@v5 + with: + name: | + crates-shielder-wasm-pkg diff --git a/.github/workflows/testnet-build-and-deploy-shielder-relayer.yml b/.github/workflows/testnet-build-and-deploy-shielder-relayer.yml new file mode 100644 index 00000000..621d8b00 --- /dev/null +++ b/.github/workflows/testnet-build-and-deploy-shielder-relayer.yml @@ -0,0 +1,43 @@ +--- +name: "[TESTNET] Build and deploy shielder-relayer" + +on: + workflow_dispatch: + +jobs: + build-and-push: + name: Build and push shielder-relayer + runs-on: [self-hosted, Linux, X64, medium] + steps: + - name: GIT | Checkout + uses: actions/checkout@v4 + + - name: DOCKER | Build and push + uses: ./.github/actions/shielder-relayer/build-and-push + id: build_shielder_relayer + with: + aws-mainnet-ecr-access-key-id: ${{ secrets.AWS_MAINNET_ECR_ACCESS_KEY_ID }} + aws-mainnet-ecr-access-key: ${{ secrets.AWS_MAINNET_ECR_ACCESS_KEY }} + ecr-private-host: ${{ secrets.ECR_PRIVATE_HOST }} + outputs: + image_tag: ${{ steps.build_shielder_relayer.outputs.image_tag }} + + deploy: + name: Deploy shielder-relayer + needs: [build-and-push] + runs-on: [self-hosted, Linux, X64, medium] + steps: + - name: GIT | Checkout + uses: actions/checkout@v4 + + - name: KUSTOMIZE | Deploy + uses: ./.github/actions/shielder-relayer/deploy + id: deploy_shielder_relayer + with: + environment: testnet-dev + image-tag: ${{ needs.build-and-push.outputs.image_tag }} + autocommit-author: ${{ secrets.AUTOCOMMIT_AUTHOR }} + autocommit-email: ${{ secrets.AUTOCOMMIT_EMAIL }} + github-token: ${{ secrets.CI_GH_TOKEN }} + kustomize-version: ${{ vars.KUSTOMIZE_VERSION }} + ecr-private-host: ${{ secrets.ECR_PRIVATE_HOST }} diff --git a/.github/workflows/testnet-nightly-e2e.yml b/.github/workflows/testnet-nightly-e2e.yml new file mode 100644 index 00000000..3f4e9cec --- /dev/null +++ b/.github/workflows/testnet-nightly-e2e.yml @@ -0,0 +1,119 @@ +--- +name: Nightly E2E tests run on testnet + +on: + schedule: + - cron: '00 23 * * *' + workflow_dispatch: + +concurrency: + group: "${{ github.ref }}-${{ github.workflow }}" + cancel-in-progress: true + +jobs: + circuits-benches: + name: Run benches for shielder-circuits crate + runs-on: [self-hosted, Linux, X64, large] + timeout-minutes: 10 + env: + RUSTC_WRAPPER: sccache + steps: + - name: Checkout source code + uses: actions/checkout@v4 + + - name: Prepare Rust env + uses: ./.github/actions/prepare-rust-env + with: + poseidon-gadget-private-key: ${{ secrets.SSH_PRIVATE_KEY }} + zkos-circuits-private-key: ${{ secrets.ZKOS_CIRCUITS_SSH_PRIVATE_KEY }} + + - name: Run benches for shielder-circuits + run: cd crates/shielder-circuits && make bench + + e2e-tests: + name: Run E2E tests on testnet + runs-on: ubuntu-22.04 + timeout-minutes: 60 + env: + RUSTC_WRAPPER: sccache + CACHE_VERSION: 1 + steps: + - name: Checkout source code + uses: actions/checkout@v4 + + - name: Restore rust cache + uses: actions/cache@v4 + with: + key: "${{ runner.os }}\ + -rust\ + -${{ env.CACHE_VERSION }}\ + -build\ + -${{ hashFiles('**/Cargo.toml') }}" + path: | + ~/.cargo/bin/ + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ + ~/.cache/sccache/ + ~/.rustup/ + target/ + restore-keys: | + ${{ runner.os }}-rust-${{ env.CACHE_VERSION }}-build- + ${{ runner.os }}-rust-${{ env.CACHE_VERSION }} + + - name: Prepare Rust env + uses: ./.github/actions/prepare-rust-env + with: + poseidon-gadget-private-key: ${{ secrets.SSH_PRIVATE_KEY }} + zkos-circuits-private-key: ${{ secrets.ZKOS_CIRCUITS_SSH_PRIVATE_KEY }} + + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1.2.0 + with: + cache-key: custom-seed-coverage-${{ github.ref_name }} + cache-restore-keys: |- + contract-suite + version: nightly-31dd1f77fd9156d09836486d97963cec7f555343 + + - name: Node deps + run: make deps + + - name: Generate Solidity contracts + run: make generate-verifier-contracts + + - name: Compile eth contracts + shell: bash + run: make compile-contracts + + - name: Run e2e tooling tests + env: + DEPLOYER_PRIVATE_KEY: ${{ secrets.CI_TESTNET_DEPLOYER_PRIVATE_KEY }} + ALICE_PUBLIC_KEY: ${{ vars.CI_TESTNET_ALICE_PUBLIC_KEY }} + ALICE_PRIVATE_KEY: ${{ secrets.CI_TESTNET_ALICE_PRIVATE_KEY }} + BOB_PUBLIC_KEY: ${{ vars.CI_TESTNET_BOB_PUBLIC_KEY }} + BOB_PRIVATE_KEY: ${{ secrets.CI_TESTNET_BOB_PRIVATE_KEY }} + CHARLIE_PUBLIC_KEY: ${{ vars.CI_TESTNET_CHARLIE_PUBLIC_KEY }} + CHARLIE_PRIVATE_KEY: ${{ secrets.CI_TESTNET_CHARLIE_PRIVATE_KEY }} + FEE_DESTINATION: ${{ vars.CI_TESTNET_FEE_DESTINATION }} + FEE_DESTINATION_KEY: ${{ secrets.CI_TESTNET_FEE_DESTINATION_KEY }} + RELAYER_SIGNER_ADDRESSES: ${{ vars.CI_TESTNET_RELAYER_SIGNER_ADDRESSES }} + RELAYER_SIGNING_KEYS: ${{ secrets.CI_TESTNET_RELAYER_SIGNING_KEYS }} + run: | + NO_FORMATTING=true TESTNET=true ./tooling-e2e-tests/full_scenario.sh + NO_FORMATTING=true TESTNET=true ./tooling-e2e-tests/recovery_scenario.sh + NO_FORMATTING=true TESTNET=true ./tooling-e2e-tests/many_actors.sh + + slack-notification: + name: Slack notification + runs-on: ubuntu-22.04 + needs: [circuits-benches, e2e-tests] + if: > + !cancelled() && + github.event_name != 'workflow_dispatch' + steps: + - name: Send Slack message + uses: Cardinal-Cryptography/github-actions/slack-notification@v7 + with: + notify-on: "failure" + env: + SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_ZKOS }} diff --git a/.github/workflows/yaml-lint.yml b/.github/workflows/yaml-lint.yml new file mode 100644 index 00000000..576ef08b --- /dev/null +++ b/.github/workflows/yaml-lint.yml @@ -0,0 +1,20 @@ +--- +name: GH Action YAML linter + +on: + pull_request: + paths: + - '.github/**.yml' + - '.github/**.yaml' + +concurrency: + group: ${{ github.ref }}-${{ github.workflow }} + cancel-in-progress: true + +jobs: + main: + name: YAML Lint + runs-on: ubuntu-22.04 + steps: + - name: LINT | Execute YAML linter + uses: Cardinal-Cryptography/github-actions/yaml-lint@v7 diff --git a/.github/workflows/yaml-validate.yml b/.github/workflows/yaml-validate.yml new file mode 100644 index 00000000..9b801b82 --- /dev/null +++ b/.github/workflows/yaml-validate.yml @@ -0,0 +1,20 @@ +--- +name: GH Action YAML validator + +on: + pull_request: + paths: + - '.github/**.yml' + - '.github/**.yaml' + +concurrency: + group: ${{ github.ref }}-${{ github.workflow }} + cancel-in-progress: true + +jobs: + main: + name: YAML Validate + runs-on: ubuntu-22.04 + steps: + - name: VALIDATE | Execute github-actions-validator + uses: Cardinal-Cryptography/github-actions/yaml-validate@v7.2.0 diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..80ebb8a1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,17 @@ +.idea/ +__pycache__/ +addresses.json +artifacts/ +broadcast/ +cache/ +node_modules/ +target/ +.DS_Store +.vscode/ +contracts/*Key.sol +contracts/*Verifier.sol +**/*output.log + +tooling-dev/* +!tooling-dev/Makefile +!tooling-dev/README.md \ No newline at end of file diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 00000000..4cbde364 --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,38 @@ +{ + "overrides": [ + { + "files": "*.sol", + "options": { + "printWidth": 80, + "tabWidth": 4, + "useTabs": false, + "singleQuote": false, + "bracketSpacing": true + } + }, + { + "files": "*.yml", + "options": {} + }, + { + "files": "*.yaml", + "options": {} + }, + { + "files": "*.toml", + "options": {} + }, + { + "files": "*.json", + "options": {} + }, + { + "files": "*.js", + "options": {} + }, + { + "files": "*.ts", + "options": {} + } + ] +} diff --git a/.solhint.json b/.solhint.json new file mode 100644 index 00000000..618f911c --- /dev/null +++ b/.solhint.json @@ -0,0 +1,21 @@ +{ + "extends": "solhint:recommended", + "plugins": ["prettier"], + "rules": { + "prettier/prettier": "error", + "quotes": ["error", "double"], + "no-inline-assembly": "", + "no-global-import": "error", + "no-empty-blocks": "", + "reason-string": "error", + "func-visibility": [ + "warn", + { + "ignoreConstructors": true + } + ], + "avoid-low-level-calls": "", + "no-unused-import": "error", + "no-unused-vars": "error" + } +} diff --git a/.tool-versions b/.tool-versions new file mode 100644 index 00000000..426afe26 --- /dev/null +++ b/.tool-versions @@ -0,0 +1 @@ +nodejs 18.19.0 \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 00000000..e4970927 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,5913 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[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 = "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 = "allocator-api2" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45862d1c77f2228b9e10bc609d5bc203d86ebc9b87ad8d5d5167a6c9abf739d9" + +[[package]] +name = "alloy-chains" +version = "0.1.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18c5c520273946ecf715c0010b4e3503d7eba9893cd9ce6b7fff5654c4a3c470" +dependencies = [ + "alloy-primitives", + "num_enum", + "strum", +] + +[[package]] +name = "alloy-consensus" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "705687d5bfd019fee57cf9e206b27b30a9a9617535d5590a02b171e813208f8e" +dependencies = [ + "alloy-eips", + "alloy-primitives", + "alloy-rlp", + "alloy-serde", + "auto_impl", + "c-kzg", + "derive_more", + "serde", +] + +[[package]] +name = "alloy-contract" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "917f7d12cf3971dc8c11c9972f732b35ccb9aaaf5f28f2f87e9e6523bee3a8ad" +dependencies = [ + "alloy-dyn-abi", + "alloy-json-abi", + "alloy-network", + "alloy-network-primitives", + "alloy-primitives", + "alloy-provider", + "alloy-rpc-types-eth", + "alloy-sol-types", + "alloy-transport", + "futures", + "futures-util", + "thiserror 1.0.69", +] + +[[package]] +name = "alloy-dyn-abi" +version = "0.8.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cf633ae9a1f0c82fdb9e559ed2be1c8e415c3e48fc47e1feaf32c6078ec0cdd" +dependencies = [ + "alloy-json-abi", + "alloy-primitives", + "alloy-sol-type-parser", + "alloy-sol-types", + "const-hex", + "itoa", + "serde", + "serde_json", + "winnow", +] + +[[package]] +name = "alloy-eip2930" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0069cf0642457f87a01a014f6dc29d5d893cd4fd8fddf0c3cdfad1bb3ebafc41" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "serde", +] + +[[package]] +name = "alloy-eip7702" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea59dc42102bc9a1905dc57901edc6dd48b9f38115df86c7d252acba70d71d04" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "k256", + "serde", +] + +[[package]] +name = "alloy-eips" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ffb906284a1e1f63c4607da2068c8197458a352d0b3e9796e67353d72a9be85" +dependencies = [ + "alloy-eip2930", + "alloy-eip7702", + "alloy-primitives", + "alloy-rlp", + "alloy-serde", + "c-kzg", + "derive_more", + "once_cell", + "serde", + "sha2", +] + +[[package]] +name = "alloy-json-abi" +version = "0.8.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a500037938085feed8a20dbfc8fce58c599db68c948cfae711147175dee392c" +dependencies = [ + "alloy-primitives", + "alloy-sol-type-parser", + "serde", + "serde_json", +] + +[[package]] +name = "alloy-json-rpc" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fa8a1a3c4cbd221f2b8e3693aeb328fca79a757fe556ed08e47bbbc2a70db7" +dependencies = [ + "alloy-primitives", + "alloy-sol-types", + "serde", + "serde_json", + "thiserror 1.0.69", + "tracing", +] + +[[package]] +name = "alloy-network" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85fa23a6a9d612b52e402c995f2d582c25165ec03ac6edf64c861a76bc5b87cd" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-json-rpc", + "alloy-network-primitives", + "alloy-primitives", + "alloy-rpc-types-eth", + "alloy-serde", + "alloy-signer", + "alloy-sol-types", + "async-trait", + "auto_impl", + "futures-utils-wasm", + "thiserror 1.0.69", +] + +[[package]] +name = "alloy-network-primitives" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "801492711d4392b2ccf5fc0bc69e299fa1aab15167d74dcaa9aab96a54f684bd" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-primitives", + "alloy-serde", + "serde", +] + +[[package]] +name = "alloy-primitives" +version = "0.8.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3aeeb5825c2fc8c2662167058347cd0cafc3cb15bcb5cdb1758a63c2dca0409e" +dependencies = [ + "alloy-rlp", + "bytes", + "cfg-if", + "const-hex", + "derive_more", + "foldhash", + "getrandom", + "hashbrown 0.15.2", + "hex-literal", + "indexmap 2.6.0", + "itoa", + "k256", + "keccak-asm", + "paste", + "proptest", + "rand", + "ruint", + "rustc-hash", + "serde", + "sha3 0.10.8", + "tiny-keccak", +] + +[[package]] +name = "alloy-provider" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcfaa4ffec0af04e3555686b8aacbcdf7d13638133a0672749209069750f78a6" +dependencies = [ + "alloy-chains", + "alloy-consensus", + "alloy-eips", + "alloy-json-rpc", + "alloy-network", + "alloy-network-primitives", + "alloy-primitives", + "alloy-rpc-client", + "alloy-rpc-types-eth", + "alloy-transport", + "alloy-transport-http", + "async-stream", + "async-trait", + "auto_impl", + "dashmap", + "futures", + "futures-utils-wasm", + "lru", + "pin-project", + "reqwest", + "serde", + "serde_json", + "thiserror 1.0.69", + "tokio", + "tracing", + "url", +] + +[[package]] +name = "alloy-rlp" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da0822426598f95e45dd1ea32a738dac057529a709ee645fcc516ffa4cbde08f" +dependencies = [ + "alloy-rlp-derive", + "arrayvec", + "bytes", +] + +[[package]] +name = "alloy-rlp-derive" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b09cae092c27b6f1bde952653a22708691802e57bfef4a2973b80bea21efd3f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", +] + +[[package]] +name = "alloy-rpc-client" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "370143ed581aace6e663342d21d209c6b2e34ee6142f7d6675adb518deeaf0dc" +dependencies = [ + "alloy-json-rpc", + "alloy-primitives", + "alloy-transport", + "alloy-transport-http", + "futures", + "pin-project", + "reqwest", + "serde", + "serde_json", + "tokio", + "tokio-stream", + "tower", + "tracing", + "url", +] + +[[package]] +name = "alloy-rpc-types" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ffc534b7919e18f35e3aa1f507b6f3d9d92ec298463a9f6beaac112809d8d06" +dependencies = [ + "alloy-primitives", + "alloy-rpc-types-engine", + "alloy-rpc-types-eth", + "alloy-serde", + "serde", +] + +[[package]] +name = "alloy-rpc-types-engine" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0285c4c09f838ab830048b780d7f4a4f460f309aa1194bb049843309524c64c" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-primitives", + "alloy-rlp", + "alloy-serde", + "derive_more", + "jsonwebtoken", + "rand", + "serde", + "strum", +] + +[[package]] +name = "alloy-rpc-types-eth" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413f4aa3ccf2c3e4234a047c5fa4727916d7daf25a89f9b765df0ba09784fd87" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-network-primitives", + "alloy-primitives", + "alloy-rlp", + "alloy-serde", + "alloy-sol-types", + "derive_more", + "itertools 0.13.0", + "serde", + "serde_json", +] + +[[package]] +name = "alloy-serde" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dff0ab1cdd43ca001e324dc27ee0e8606bd2161d6623c63e0e0b8c4dfc13600" +dependencies = [ + "alloy-primitives", + "serde", + "serde_json", +] + +[[package]] +name = "alloy-signer" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd4e0ad79c81a27ca659be5d176ca12399141659fef2bcbfdc848da478f4504" +dependencies = [ + "alloy-primitives", + "async-trait", + "auto_impl", + "elliptic-curve", + "k256", + "thiserror 1.0.69", +] + +[[package]] +name = "alloy-signer-local" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "494e0a256f3e99f2426f994bcd1be312c02cb8f88260088dacb33a8b8936475f" +dependencies = [ + "alloy-consensus", + "alloy-network", + "alloy-primitives", + "alloy-signer", + "async-trait", + "k256", + "rand", + "thiserror 1.0.69", +] + +[[package]] +name = "alloy-sol-macro" +version = "0.8.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c0279d09463a4695788a3622fd95443625f7be307422deba4b55dd491a9c7a1" +dependencies = [ + "alloy-sol-macro-expander", + "alloy-sol-macro-input", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.89", +] + +[[package]] +name = "alloy-sol-macro-expander" +version = "0.8.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4feea540fc8233df2ad1156efd744b2075372f43a8f942a68b3b19c8a00e2c12" +dependencies = [ + "alloy-json-abi", + "alloy-sol-macro-input", + "const-hex", + "heck", + "indexmap 2.6.0", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.89", + "syn-solidity", + "tiny-keccak", +] + +[[package]] +name = "alloy-sol-macro-input" +version = "0.8.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a0ad281f3d1b613af814b66977ee698e443d4644a1510962d0241f26e0e53ae" +dependencies = [ + "alloy-json-abi", + "const-hex", + "dunce", + "heck", + "proc-macro2", + "quote", + "serde_json", + "syn 2.0.89", + "syn-solidity", +] + +[[package]] +name = "alloy-sol-type-parser" +version = "0.8.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96eff16c797438add6c37bb335839d015b186c5421ee5626f5559a7bfeb38ef5" +dependencies = [ + "serde", + "winnow", +] + +[[package]] +name = "alloy-sol-types" +version = "0.8.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff34e0682d6665da243a3e81da96f07a2dd50f7e64073e382b1a141f5a2a2f6" +dependencies = [ + "alloy-json-abi", + "alloy-primitives", + "alloy-sol-macro", + "const-hex", + "serde", +] + +[[package]] +name = "alloy-transport" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ac3e97dad3d31770db0fc89bd6a63b789fbae78963086733f960cf32c483904" +dependencies = [ + "alloy-json-rpc", + "base64 0.22.1", + "futures-util", + "futures-utils-wasm", + "serde", + "serde_json", + "thiserror 1.0.69", + "tokio", + "tower", + "tracing", + "url", +] + +[[package]] +name = "alloy-transport-http" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b367dcccada5b28987c2296717ee04b9a5637aacd78eacb1726ef211678b5212" +dependencies = [ + "alloy-json-rpc", + "alloy-transport", + "reqwest", + "serde_json", + "tower", + "tracing", + "url", +] + +[[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.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" +dependencies = [ + "anstyle", + "windows-sys 0.59.0", +] + +[[package]] +name = "anyhow" +version = "1.0.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" + +[[package]] +name = "ark-ff" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b3235cc41ee7a12aaaf2c575a2ad7b46713a8a50bda2fc3b003a04845c05dd6" +dependencies = [ + "ark-ff-asm 0.3.0", + "ark-ff-macros 0.3.0", + "ark-serialize 0.3.0", + "ark-std 0.3.0", + "derivative", + "num-bigint", + "num-traits", + "paste", + "rustc_version 0.3.3", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +dependencies = [ + "ark-ff-asm 0.4.2", + "ark-ff-macros 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", + "derivative", + "digest 0.10.7", + "itertools 0.10.5", + "num-bigint", + "num-traits", + "paste", + "rustc_version 0.4.1", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db02d390bf6643fb404d3d22d31aee1c4bc4459600aef9113833d17e786c6e44" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-asm" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fd794a08ccb318058009eefdf15bcaaaaf6f8161eb3345f907222bac38b20" +dependencies = [ + "num-bigint", + "num-traits", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-serialize" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6c2b318ee6e10f8c2853e73a83adc0ccb88995aa978d8a3408d492ab2ee671" +dependencies = [ + "ark-std 0.3.0", + "digest 0.9.0", +] + +[[package]] +name = "ark-serialize" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +dependencies = [ + "ark-std 0.4.0", + "digest 0.10.7", + "num-bigint", +] + +[[package]] +name = "ark-std" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c" +dependencies = [ + "num-traits", + "rand", +] + +[[package]] +name = "ark-std" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand", +] + +[[package]] +name = "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 = "askama" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b79091df18a97caea757e28cd2d5fda49c6cd4bd01ddffd7ff01ace0c0ad2c28" +dependencies = [ + "askama_derive", + "askama_escape", +] + +[[package]] +name = "askama_derive" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19fe8d6cb13c4714962c072ea496f3392015f0989b1a2847bb4b2d9effd71d83" +dependencies = [ + "askama_parser", + "basic-toml", + "mime", + "mime_guess", + "proc-macro2", + "quote", + "serde", + "syn 2.0.89", +] + +[[package]] +name = "askama_escape" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341" + +[[package]] +name = "askama_parser" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acb1161c6b64d1c3d83108213c2a2533a342ac225aabd0bda218278c2ddb00c0" +dependencies = [ + "nom", +] + +[[package]] +name = "async-channel" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" +dependencies = [ + "concurrent-queue", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", +] + +[[package]] +name = "async-trait" +version = "0.1.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "aurora-engine-modexp" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0aef7712851e524f35fbbb74fa6599c5cd8692056a1c36f9ca0d2001b670e7e5" +dependencies = [ + "hex", + "num", +] + +[[package]] +name = "auto_impl" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", +] + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "axum" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f" +dependencies = [ + "async-trait", + "axum-core", + "bytes", + "futures-util", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-util", + "itoa", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", + "sync_wrapper 1.0.2", + "tokio", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "axum-core" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http", + "http-body", + "http-body-util", + "mime", + "pin-project-lite", + "rustversion", + "sync_wrapper 1.0.2", + "tower-layer", + "tower-service", + "tracing", +] + +[[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 = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[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 = "basic-toml" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "823388e228f614e9558c6804262db37960ec8821856535f5c3f59913140558f8" +dependencies = [ + "serde", +] + +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "blake2b_simd" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23285ad32269793932e830392f2fe2f83e26488fd3ec778883a93c8323735780" +dependencies = [ + "arrayref", + "arrayvec", + "constant_time_eq", +] + +[[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 = "blst" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4378725facc195f1a538864863f6de233b500a8862747e7f165078a419d5e874" +dependencies = [ + "cc", + "glob", + "threadpool", + "zeroize", +] + +[[package]] +name = "bollard" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0aed08d3adb6ebe0eff737115056652670ae290f177759aac19c30456135f94c" +dependencies = [ + "base64 0.22.1", + "bollard-stubs", + "bytes", + "futures-core", + "futures-util", + "hex", + "home", + "http", + "http-body-util", + "hyper", + "hyper-named-pipe", + "hyper-rustls 0.26.0", + "hyper-util", + "hyperlocal-next", + "log", + "pin-project-lite", + "rustls 0.22.4", + "rustls-native-certs 0.7.3", + "rustls-pemfile", + "rustls-pki-types", + "serde", + "serde_derive", + "serde_json", + "serde_repr", + "serde_urlencoded", + "thiserror 1.0.69", + "tokio", + "tokio-util", + "tower-service", + "url", + "winapi", +] + +[[package]] +name = "bollard-stubs" +version = "1.44.0-rc.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "709d9aa1c37abb89d40f19f5d0ad6f0d88cb1581264e571c9350fc5bb89cf1c5" +dependencies = [ + "serde", + "serde_repr", + "serde_with", +] + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[package]] +name = "byte-slice-cast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" + +[[package]] +name = "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" +dependencies = [ + "serde", +] + +[[package]] +name = "c-kzg" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0307f72feab3300336fb803a57134159f6e20139af1357f36c54cb90d8e8928" +dependencies = [ + "blst", + "cc", + "glob", + "hex", + "libc", + "once_cell", + "serde", +] + +[[package]] +name = "cc" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd9de9f2205d5ef3fd67e685b0df337994ddd4495e2a28d185500d0e1edfea47" +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 = "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.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +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.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.89", +] + +[[package]] +name = "clap_lex" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7" + +[[package]] +name = "colorchoice" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" + +[[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_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 = "const-hex" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "487981fa1af147182687064d0a2c336586d337a606595ced9ffb0c685c250c73" +dependencies = [ + "cfg-if", + "cpufeatures", + "hex", + "proptest", + "serde", +] + +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "constant_time_eq" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" + +[[package]] +name = "content-encryption" +version = "0.1.0" +dependencies = [ + "anyhow", + "chacha20poly1305", + "rust-argon2", +] + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63" +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 = "crossbeam-channel" +version = "0.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + +[[package]] +name = "crossterm" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e64e6c0fbe2c17357405f7c758c1ef960fce08bdfb2c03d88d2a18d7e09c4b67" +dependencies = [ + "bitflags 1.3.2", + "crossterm_winapi", + "libc", + "mio 0.8.11", + "parking_lot", + "signal-hook", + "signal-hook-mio", + "winapi", +] + +[[package]] +name = "crossterm_winapi" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" +dependencies = [ + "winapi", +] + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "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.89", +] + +[[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.89", +] + +[[package]] +name = "dashmap" +version = "6.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", +] + +[[package]] +name = "data-encoding" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" + +[[package]] +name = "der" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", + "serde", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_more" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" +dependencies = [ + "derive_more-impl", +] + +[[package]] +name = "derive_more-impl" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", + "unicode-xid", +] + +[[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 = "dirs" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.48.0", +] + +[[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.89", +] + +[[package]] +name = "docker_credential" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31951f49556e34d90ed28342e1df7e1cb7a229c4cab0aecc627b5d91edd41d07" +dependencies = [ + "base64 0.21.7", + "serde", + "serde_json", +] + +[[package]] +name = "downcast" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1" + +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + +[[package]] +name = "dyn-clone" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest 0.10.7", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest 0.10.7", + "ff", + "generic-array", + "group", + "pkcs8", + "rand_core", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "encoding_rs" +version = "0.8.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "enum-as-inner" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.89", +] + +[[package]] +name = "enumn" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f9ed6b3789237c8a0c1c505af1c7eb2c560df6186f01b098c3a1064ea532f38" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "event-listener" +version = "5.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" +dependencies = [ + "event-listener", + "pin-project-lite", +] + +[[package]] +name = "evm-utils" +version = "0.1.0" +dependencies = [ + "alloy-sol-types", + "hex", + "revm", + "revm-interpreter", + "revm-precompile", + "revm-primitives", + "sha3 0.10.8", + "thiserror 1.0.69", +] + +[[package]] +name = "fastrand" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" + +[[package]] +name = "fastrlp" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139834ddba373bbdd213dffe02c8d110508dcf1726c2be27e8d1f7d7e1856418" +dependencies = [ + "arrayvec", + "auto_impl", + "bytes", +] + +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "bitvec", + "rand_core", + "subtle", +] + +[[package]] +name = "fixed-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" +dependencies = [ + "byteorder", + "rand", + "rustc-hex", + "static_assertions", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" + +[[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 = "fragile" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futures" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-executor" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-macro" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", +] + +[[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 = "futures-utils-wasm" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42012b0f064e01aa58b545fe3727f90f7dd4020f4a3ea735b50344965f5a57e9" + +[[package]] +name = "fuzzy-matcher" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54614a3312934d066701a80f20f15fa3b56d67ac7722b39eea5b4c9dd1d66c94" +dependencies = [ + "thread_local", +] + +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "gimli" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core", + "subtle", +] + +[[package]] +name = "h2" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccae279728d634d083c00f6099cb58f01cc99c145b84b8be2f6c74618d79922e" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http", + "indexmap 2.6.0", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "halo2_poseidon" +version = "0.2.0" +source = "git+ssh://git@github.com/Cardinal-Cryptography/poseidon-gadget?branch=poseidon2-pow7#af9a8b342b2d3b1f9074d09840171677dd9077ec" +dependencies = [ + "arrayvec", + "bitvec", + "ff", + "group", + "halo2_proofs", + "halo2curves", + "hex", + "lazy_static", + "rand", + "subtle", + "uint", +] + +[[package]] +name = "halo2_proofs" +version = "0.3.0" +source = "git+https://github.com/privacy-scaling-explorations/halo2?tag=v0.3.0#73408a140737d8336490452193b21f5a7a94e7de" +dependencies = [ + "blake2b_simd", + "ff", + "group", + "halo2curves", + "rand_chacha", + "rand_core", + "rayon", + "serde", + "serde_derive", + "sha3 0.9.1", + "tracing", +] + +[[package]] +name = "halo2_solidity_verifier" +version = "0.2.0" +dependencies = [ + "alloy-primitives", + "alloy-sol-types", + "askama", + "evm-utils", + "halo2_proofs", + "itertools 0.13.0", + "rand", + "ruint", + "shielder-circuits", + "shielder-rust-sdk", +] + +[[package]] +name = "halo2curves" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db81d01d0bbfec9f624d7590fc6929ee2537a64ec1e080d8f8c9e2d2da291405" +dependencies = [ + "blake2b_simd", + "ff", + "group", + "lazy_static", + "num-bigint", + "num-traits", + "pairing", + "pasta_curves", + "paste", + "rand", + "rand_core", + "rayon", + "static_assertions", + "subtle", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash", +] + +[[package]] +name = "hashbrown" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", + "serde", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +dependencies = [ + "serde", +] + +[[package]] +name = "hex-literal" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" + +[[package]] +name = "hickory-proto" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07698b8420e2f0d6447a436ba999ec85d8fbf2a398bbd737b82cac4a2e96e512" +dependencies = [ + "async-trait", + "cfg-if", + "data-encoding", + "enum-as-inner", + "futures-channel", + "futures-io", + "futures-util", + "idna 0.4.0", + "ipnet", + "once_cell", + "rand", + "thiserror 1.0.69", + "tinyvec", + "tokio", + "tracing", + "url", +] + +[[package]] +name = "hickory-resolver" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28757f23aa75c98f254cf0405e6d8c25b831b32921b050a66692427679b1f243" +dependencies = [ + "cfg-if", + "futures-util", + "hickory-proto", + "ipconfig", + "lru-cache", + "once_cell", + "parking_lot", + "rand", + "resolv-conf", + "smallvec", + "thiserror 1.0.69", + "tokio", + "tracing", +] + +[[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 = "home" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "hostname" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" +dependencies = [ + "libc", + "match_cfg", + "winapi", +] + +[[package]] +name = "http" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "http-body-util" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +dependencies = [ + "bytes", + "futures-util", + "http", + "http-body", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.9.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 = "human_bytes" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91f255a4535024abf7640cb288260811fc14794f62b063652ed349f9a6c2348e" + +[[package]] +name = "hyper" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97818827ef4f364230e16705d4706e2897df2bb60617d6ca15d598025a3c481f" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-named-pipe" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73b7d8abf35697b81a825e386fc151e0d503e8cb5fcb93cc8669c376dfd6f278" +dependencies = [ + "hex", + "hyper", + "hyper-util", + "pin-project-lite", + "tokio", + "tower-service", + "winapi", +] + +[[package]] +name = "hyper-rustls" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0bea761b46ae2b24eb4aef630d8d1c398157b6fc29e6350ecf090a0b70c952c" +dependencies = [ + "futures-util", + "http", + "hyper", + "hyper-util", + "log", + "rustls 0.22.4", + "rustls-native-certs 0.7.3", + "rustls-pki-types", + "tokio", + "tokio-rustls 0.25.0", + "tower-service", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" +dependencies = [ + "futures-util", + "http", + "hyper", + "hyper-util", + "rustls 0.23.19", + "rustls-native-certs 0.8.1", + "rustls-pki-types", + "tokio", + "tokio-rustls 0.26.0", + "tower-service", + "webpki-roots", +] + +[[package]] +name = "hyper-tls" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" +dependencies = [ + "bytes", + "http-body-util", + "hyper", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http", + "http-body", + "hyper", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", +] + +[[package]] +name = "hyperlocal-next" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acf569d43fa9848e510358c07b80f4adf34084ddc28c6a4a651ee8474c070dcc" +dependencies = [ + "hex", + "http-body-util", + "hyper", + "hyper-util", + "pin-project-lite", + "tokio", + "tower-service", +] + +[[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.89", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[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 = "impl-codec" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" +dependencies = [ + "parity-scale-codec", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", +] + +[[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.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +dependencies = [ + "equivalent", + "hashbrown 0.15.2", + "serde", +] + +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + +[[package]] +name = "inquire" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fddf93031af70e75410a2511ec04d49e758ed2f26dad3404a934e0fb45cc12a" +dependencies = [ + "bitflags 2.6.0", + "crossterm", + "dyn-clone", + "fuzzy-matcher", + "fxhash", + "newline-converter", + "once_cell", + "unicode-segmentation", + "unicode-width", +] + +[[package]] +name = "integration-tests" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-sol-types", + "evm-utils", + "halo2_proofs", + "halo2_solidity_verifier", + "hex", + "rand", + "rstest", + "serde", + "serde_json", + "shielder-circuits", + "shielder-rust-sdk", +] + +[[package]] +name = "ipconfig" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" +dependencies = [ + "socket2", + "widestring", + "windows-sys 0.48.0", + "winreg", +] + +[[package]] +name = "ipnet" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" + +[[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.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +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.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "jsonwebtoken" +version = "9.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ae10193d25051e74945f1ea2d0b42e03cc3b890f7e4cc5faa44997d808193f" +dependencies = [ + "base64 0.21.7", + "js-sys", + "pem", + "ring", + "serde", + "serde_json", + "simple_asn1", +] + +[[package]] +name = "k256" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "once_cell", + "sha2", +] + +[[package]] +name = "keccak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "keccak-asm" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "505d1856a39b200489082f90d897c3f07c455563880bc5952e38eabf731c83b6" +dependencies = [ + "digest 0.10.7", + "sha3-asm", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin", +] + +[[package]] +name = "libc" +version = "0.2.166" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2ccc108bbc0b1331bd061864e7cd823c0cab660bbe6970e66e2c0614decde36" + +[[package]] +name = "libm" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" + +[[package]] +name = "libredox" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags 2.6.0", + "libc", +] + +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[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.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "lru" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" +dependencies = [ + "hashbrown 0.15.2", +] + +[[package]] +name = "lru-cache" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" +dependencies = [ + "linked-hash-map", +] + +[[package]] +name = "match_cfg" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" + +[[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 = "matchit" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "metrics" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "884adb57038347dfbaf2d5065887b6cf4312330dc8e94bc30a1a839bd79d3261" +dependencies = [ + "ahash", + "portable-atomic", +] + +[[package]] +name = "metrics-exporter-prometheus" +version = "0.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4f0c8427b39666bf970460908b213ec09b3b350f20c0c2eabcbba51704a08e6" +dependencies = [ + "base64 0.22.1", + "indexmap 2.6.0", + "metrics", + "metrics-util", + "quanta", + "thiserror 1.0.69", +] + +[[package]] +name = "metrics-util" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4259040465c955f9f2f1a4a8a16dc46726169bca0f88e8fb2dbeced487c3e828" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", + "hashbrown 0.14.5", + "metrics", + "num_cpus", + "quanta", + "sketches-ddsketch", +] + +[[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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +dependencies = [ + "adler2", +] + +[[package]] +name = "mio" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +dependencies = [ + "libc", + "log", + "wasi", + "windows-sys 0.48.0", +] + +[[package]] +name = "mio" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" +dependencies = [ + "hermit-abi", + "libc", + "wasi", + "windows-sys 0.52.0", +] + +[[package]] +name = "mockall" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39a6bfcc6c8c7eed5ee98b9c3e33adc726054389233e201c95dab2d41a3839d2" +dependencies = [ + "cfg-if", + "downcast", + "fragile", + "mockall_derive", + "predicates", + "predicates-tree", +] + +[[package]] +name = "mockall_derive" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25ca3004c2efe9011bd4e461bd8256445052b9615405b4f7ea43fc8ca5c20898" +dependencies = [ + "cfg-if", + "proc-macro2", + "quote", + "syn 2.0.89", +] + +[[package]] +name = "native-tls" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework 2.11.1", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "newline-converter" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b6b097ecb1cbfed438542d16e84fd7ad9b0c76c8a65b7f9039212a3d14dc7f" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + +[[package]] +name = "num" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "num_cpus" +version = "1.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-macro2", + "quote", + "syn 2.0.89", +] + +[[package]] +name = "object" +version = "0.36.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" +dependencies = [ + "memchr", +] + +[[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.6.0", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[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 = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + +[[package]] +name = "pairing" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fec4625e73cf41ef4bb6846cafa6d44736525f442ba45e407c4a000a13996f" +dependencies = [ + "group", +] + +[[package]] +name = "parity-scale-codec" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be4817d39f3272f69c59fe05d0535ae6456c2dc2fa1ba02910296c7e0a5c590" +dependencies = [ + "arrayvec", + "bitvec", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "rustversion", + "serde", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8781a75c6205af67215f382092b6e0a4ff3734798523e69073d4bcd294ec767b" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.89", +] + +[[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 = "parse-display" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "914a1c2265c98e2446911282c6ac86d8524f495792c38c5bd884f80499c7538a" +dependencies = [ + "parse-display-derive", + "regex", + "regex-syntax 0.8.5", +] + +[[package]] +name = "parse-display-derive" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ae7800a4c974efd12df917266338e79a7a74415173caf7e70aa0a0707345281" +dependencies = [ + "proc-macro2", + "quote", + "regex", + "regex-syntax 0.8.5", + "structmeta", + "syn 2.0.89", +] + +[[package]] +name = "pasta_curves" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e57598f73cc7e1b2ac63c79c517b31a0877cd7c402cdcaa311b5208de7a095" +dependencies = [ + "blake2b_simd", + "ff", + "group", + "lazy_static", + "rand", + "static_assertions", + "subtle", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pem" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e459365e590736a54c3fa561947c84837534b8e9af6fc5bf781307e82658fae" +dependencies = [ + "base64 0.22.1", + "serde", +] + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pest" +version = "2.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879952a81a83930934cbf1786752d6dedc3b1f29e8f8fb2ad1d0a36f377cf442" +dependencies = [ + "memchr", + "thiserror 1.0.69", + "ucd-trie", +] + +[[package]] +name = "pin-project" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be57f64e946e500c8ee36ef6331845d40a93055567ec57e8fae13efd33759b95" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "pkg-config" +version = "0.3.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 = "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 = "predicates" +version = "3.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e9086cc7640c29a356d1a29fd134380bee9d8f79a17410aa76e7ad295f42c97" +dependencies = [ + "anstyle", + "predicates-core", +] + +[[package]] +name = "predicates-core" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae8177bee8e75d6846599c6b9ff679ed51e882816914eec639944d7c9aa11931" + +[[package]] +name = "predicates-tree" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41b740d195ed3166cd147c8047ec98db0e22ec019eb8eeb76d343b795304fb13" +dependencies = [ + "predicates-core", + "termtree", +] + +[[package]] +name = "primitive-types" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" +dependencies = [ + "fixed-hash", + "impl-codec", + "uint", +] + +[[package]] +name = "proc-macro-crate" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", + "syn 2.0.89", +] + +[[package]] +name = "proc-macro2" +version = "1.0.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "proptest" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4c2511913b88df1637da85cc8d96ec8e43a3f8bb8ccb71ee1ac240d6f3df58d" +dependencies = [ + "bit-set", + "bit-vec", + "bitflags 2.6.0", + "lazy_static", + "num-traits", + "rand", + "rand_chacha", + "rand_xorshift", + "regex-syntax 0.8.5", + "rusty-fork", + "tempfile", + "unarray", +] + +[[package]] +name = "quanta" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5167a477619228a0b284fac2674e3c388cba90631d7b7de620e6f1fcd08da5" +dependencies = [ + "crossbeam-utils", + "libc", + "once_cell", + "raw-cpuid", + "wasi", + "web-sys", + "winapi", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "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.19", + "socket2", + "thiserror 2.0.3", + "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", + "rand", + "ring", + "rustc-hash", + "rustls 0.23.19", + "rustls-pki-types", + "slab", + "thiserror 2.0.3", + "tinyvec", + "tracing", + "web-time", +] + +[[package]] +name = "quinn-udp" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5a626c6807713b15cac82a6acaccd6043c9a5408c24baae07611fec3f243da" +dependencies = [ + "cfg_aliases", + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.59.0", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", + "serde", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_xorshift" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +dependencies = [ + "rand_core", +] + +[[package]] +name = "raw-cpuid" +version = "11.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ab240315c661615f2ee9f0f2cd32d5a7343a84d5ebcccb99d46e6637565e7b0" +dependencies = [ + "bitflags 2.6.0", +] + +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", + "wasm_sync", +] + +[[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", + "wasm_sync", +] + +[[package]] +name = "redox_syscall" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" +dependencies = [ + "bitflags 2.6.0", +] + +[[package]] +name = "redox_users" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" +dependencies = [ + "getrandom", + "libredox", + "thiserror 1.0.69", +] + +[[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 = "relative-path" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2" + +[[package]] +name = "reqwest" +version = "0.12.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f713147fbe92361e52392c73b8c9e48c04c6625bce969ef54dc901e58e042a7b" +dependencies = [ + "base64 0.22.1", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "hickory-resolver", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls 0.27.3", + "hyper-tls", + "hyper-util", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "quinn", + "rustls 0.23.19", + "rustls-native-certs 0.8.1", + "rustls-pemfile", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper 1.0.2", + "system-configuration", + "tokio", + "tokio-native-tls", + "tokio-rustls 0.26.0", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots", + "windows-registry", +] + +[[package]] +name = "resolv-conf" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52e44394d2086d010551b14b53b1f24e31647570cd1deb0379e2c21b329aba00" +dependencies = [ + "hostname", + "quick-error", +] + +[[package]] +name = "revm" +version = "14.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "641702b12847f9ed418d552f4fcabe536d867a2c980e96b6e7e25d7b992f929f" +dependencies = [ + "auto_impl", + "cfg-if", + "dyn-clone", + "revm-interpreter", + "revm-precompile", + "serde", + "serde_json", +] + +[[package]] +name = "revm-interpreter" +version = "10.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e5e14002afae20b5bf1566f22316122f42f57517000e559c55b25bf7a49cba2" +dependencies = [ + "revm-primitives", + "serde", +] + +[[package]] +name = "revm-precompile" +version = "11.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3198c06247e8d4ad0d1312591edf049b0de4ddffa9fecb625c318fd67db8639b" +dependencies = [ + "aurora-engine-modexp", + "c-kzg", + "cfg-if", + "k256", + "once_cell", + "revm-primitives", + "ripemd", + "secp256k1", + "sha2", + "substrate-bn", +] + +[[package]] +name = "revm-primitives" +version = "10.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f1525851a03aff9a9d6a1d018b414d76252d6802ab54695b27093ecd7e7a101" +dependencies = [ + "alloy-eip2930", + "alloy-eip7702", + "alloy-primitives", + "auto_impl", + "bitflags 2.6.0", + "bitvec", + "cfg-if", + "dyn-clone", + "enumn", + "hex", + "serde", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "ring" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +dependencies = [ + "cc", + "cfg-if", + "getrandom", + "libc", + "spin", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "ripemd" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "rlp" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" +dependencies = [ + "bytes", + "rustc-hex", +] + +[[package]] +name = "rstest" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a2c585be59b6b5dd66a9d2084aa1d8bd52fbdb806eafdeffb52791147862035" +dependencies = [ + "futures", + "futures-timer", + "rstest_macros", + "rustc_version 0.4.1", +] + +[[package]] +name = "rstest_macros" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "825ea780781b15345a146be27eaefb05085e337e869bff01b4306a4fd4a9ad5a" +dependencies = [ + "cfg-if", + "glob", + "proc-macro-crate", + "proc-macro2", + "quote", + "regex", + "relative-path", + "rustc_version 0.4.1", + "syn 2.0.89", + "unicode-ident", +] + +[[package]] +name = "ruint" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c3cc4c2511671f327125da14133d0c5c5d137f006a1017a16f557bc85b16286" +dependencies = [ + "alloy-rlp", + "ark-ff 0.3.0", + "ark-ff 0.4.2", + "bytes", + "fastrlp", + "num-bigint", + "num-traits", + "parity-scale-codec", + "primitive-types", + "proptest", + "rand", + "rlp", + "ruint-macro", + "serde", + "valuable", + "zeroize", +] + +[[package]] +name = "ruint-macro" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48fd7bd8a6377e15ad9d42a8ec25371b94ddc67abe7c8b9127bec79bebaaae18" + +[[package]] +name = "rust-argon2" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d9848531d60c9cbbcf9d166c885316c24bc0e2a9d3eba0956bb6cbbd79bc6e8" +dependencies = [ + "base64 0.21.7", + "blake2b_simd", + "constant_time_eq", +] + +[[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.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" +dependencies = [ + "rand", +] + +[[package]] +name = "rustc-hex" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" + +[[package]] +name = "rustc_version" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" +dependencies = [ + "semver 0.11.0", +] + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver 1.0.23", +] + +[[package]] +name = "rustix" +version = "0.38.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7f649912bc1495e167a6edee79151c84b1bad49748cb4f1f1167f459f6224f6" +dependencies = [ + "bitflags 2.6.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustls" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432" +dependencies = [ + "log", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls" +version = "0.23.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "934b404430bb06b3fae2cba809eb45a1ab1aecd64491213d7c3301b88393f8d1" +dependencies = [ + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "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", + "rustls-pki-types", + "schannel", + "security-framework 2.11.1", +] + +[[package]] +name = "rustls-native-certs" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework 3.0.1", +] + +[[package]] +name = "rustls-pemfile" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" +dependencies = [ + "web-time", +] + +[[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.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" + +[[package]] +name = "rusty-fork" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" +dependencies = [ + "fnv", + "quick-error", + "tempfile", + "wait-timeout", +] + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "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 = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "secp256k1" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9465315bc9d4566e1724f0fffcbcc446268cb522e60f9a27bcded6b19c108113" +dependencies = [ + "rand", + "secp256k1-sys", +] + +[[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.6.0", + "core-foundation 0.9.4", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1415a607e92bec364ea2cf9264646dcce0f91e6d65281bd6f2819cca3bf39c8" +dependencies = [ + "bitflags 2.6.0", + "core-foundation 0.10.0", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa39c7303dc58b5543c94d22c1766b0d31f2ee58306363ea622b10bbc075eaa2" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" + +[[package]] +name = "semver-parser" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9900206b54a3527fdc7b8a938bffd94a568bac4f4aa8113b209df75a09c0dec2" +dependencies = [ + "pest", +] + +[[package]] +name = "serde" +version = "1.0.215" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.215" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", +] + +[[package]] +name = "serde_json" +version = "1.0.133" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" +dependencies = [ + "indexmap 2.6.0", + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_path_to_error" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af99884400da37c88f5e9146b7f1fd0fbcae8f6eec4e9da38b67d05486f814a6" +dependencies = [ + "itoa", + "serde", +] + +[[package]] +name = "serde_repr" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", +] + +[[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.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e28bdad6db2b8340e449f7108f020b3b092e8583a9e3fb82713e1d4e71fe817" +dependencies = [ + "base64 0.22.1", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.6.0", + "serde", + "serde_derive", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d846214a9854ef724f3da161b426242d8de7c1fc7de2f89bb1efcb154dca79d" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.89", +] + +[[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 = "sha3-asm" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28efc5e327c837aa837c59eae585fc250715ef939ac32881bcc11677cd02d46" +dependencies = [ + "cc", + "cfg-if", +] + +[[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 = "shellexpand" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da03fa3b94cc19e3ebfc88c4229c49d8f08cdbd1228870a45f0ffdf84988e14b" +dependencies = [ + "dirs", +] + +[[package]] +name = "shielder-circuits" +version = "0.1.0" +source = "git+ssh://git@github.com/Cardinal-Cryptography/zkOS-circuits?branch=main#744505c7e4fbb615c6db46500e6d2a3b02253a6a" +dependencies = [ + "console_error_panic_hook", + "halo2_poseidon", + "halo2_proofs", + "human_bytes", + "once_cell", + "rand", + "rand_chacha", + "rand_core", + "rayon", + "sha2", + "static_assertions", + "strum", + "strum_macros", + "thiserror 1.0.69", + "transcript", +] + +[[package]] +name = "shielder-cli" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-eips", + "alloy-network", + "alloy-primitives", + "alloy-provider", + "alloy-rpc-types-eth", + "alloy-signer-local", + "alloy-sol-types", + "anyhow", + "clap", + "content-encryption", + "inquire", + "rand", + "reqwest", + "serde", + "serde_json", + "shellexpand", + "shielder-circuits", + "shielder-relayer", + "shielder-rust-sdk", + "tokio", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "shielder-relayer" +version = "0.1.0" +dependencies = [ + "alloy-provider", + "alloy-rpc-types", + "alloy-signer", + "alloy-signer-local", + "anyhow", + "async-channel", + "axum", + "clap", + "metrics", + "metrics-exporter-prometheus", + "openssl", + "rand", + "reqwest", + "serde", + "serde_json", + "shielder-rust-sdk", + "testcontainers", + "tokio", + "tower-http", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "shielder-rust-sdk" +version = "0.1.0" +dependencies = [ + "alloy-contract", + "alloy-network", + "alloy-primitives", + "alloy-provider", + "alloy-rpc-types", + "alloy-signer-local", + "alloy-sol-types", + "alloy-transport", + "anyhow", + "byteorder", + "halo2_proofs", + "halo2curves", + "hex", + "lazy_static", + "log", + "mockall", + "num-bigint", + "rand", + "secp256k1", + "serde", + "sha3 0.10.8", + "shielder-circuits", + "static_assertions", + "thiserror 1.0.69", + "tokio", + "tracing", +] + +[[package]] +name = "shielder-wasm" +version = "0.1.0" +dependencies = [ + "console_error_panic_hook", + "getrandom", + "halo2_poseidon", + "halo2_proofs", + "rand", + "rand_chacha", + "rand_core", + "rayon", + "sha2", + "shielder-circuits", + "shielder-rust-sdk", + "wasm-bindgen", + "wasm-bindgen-rayon", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-mio" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34db1a06d485c9142248b7a054f034b349b212551f3dfd19c94d45a754a217cd" +dependencies = [ + "libc", + "mio 0.8.11", + "signal-hook", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +dependencies = [ + "libc", +] + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest 0.10.7", + "rand_core", +] + +[[package]] +name = "simple_asn1" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085" +dependencies = [ + "num-bigint", + "num-traits", + "thiserror 1.0.69", + "time", +] + +[[package]] +name = "sketches-ddsketch" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85636c14b73d81f541e525f585c0a2109e6744e1565b5c1668e31c70c10ed65c" + +[[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 = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "stress-testing" +version = "0.1.0" +dependencies = [ + "alloy-provider", + "alloy-rpc-types", + "alloy-signer-local", + "anyhow", + "clap", + "rand", + "reqwest", + "shielder-circuits", + "shielder-relayer", + "shielder-rust-sdk", + "tokio", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "structmeta" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e1575d8d40908d70f6fd05537266b90ae71b15dbbe7a8b7dffa2b759306d329" +dependencies = [ + "proc-macro2", + "quote", + "structmeta-derive", + "syn 2.0.89", +] + +[[package]] +name = "structmeta-derive" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "152a0b65a590ff6c3da95cabe2353ee04e6167c896b28e3b14478c2636c922fc" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", +] + +[[package]] +name = "strum" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.89", +] + +[[package]] +name = "substrate-bn" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b5bbfa79abbae15dd642ea8176a21a635ff3c00059961d1ea27ad04e5b441c" +dependencies = [ + "byteorder", + "crunchy", + "lazy_static", + "rand", + "rustc-hex", +] + +[[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.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d46482f1c1c87acd84dea20c1bf5ebff4c757009ed6bf19cfd36fb10e92c4e" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn-solidity" +version = "0.8.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdaa7b9e815582ba343a20c66627437cf45f1c6fba7f69772cbfd1358c7e197" +dependencies = [ + "paste", + "proc-macro2", + "quote", + "syn 2.0.89", +] + +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", +] + +[[package]] +name = "system-configuration" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" +dependencies = [ + "bitflags 2.6.0", + "core-foundation 0.9.4", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "tempfile" +version = "3.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" +dependencies = [ + "cfg-if", + "fastrand", + "once_cell", + "rustix", + "windows-sys 0.59.0", +] + +[[package]] +name = "termtree" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" + +[[package]] +name = "test-ts-conversions" +version = "0.1.0" +dependencies = [ + "clap", + "halo2_proofs", + "shielder-circuits", + "shielder-rust-sdk", +] + +[[package]] +name = "testcontainers" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81abdf87437235a275fd0fecaa6ca2c6af28240506e695e9abe84597b3431b35" +dependencies = [ + "async-trait", + "bollard", + "bollard-stubs", + "bytes", + "dirs", + "docker_credential", + "either", + "futures", + "log", + "memchr", + "parse-display", + "reqwest", + "serde", + "serde_json", + "serde_with", + "thiserror 1.0.69", + "tokio", + "tokio-stream", + "tokio-util", + "url", +] + +[[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.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c006c85c7651b3cf2ada4584faa36773bd07bac24acfb39f3c431b36d7e667aa" +dependencies = [ + "thiserror-impl 2.0.3", +] + +[[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.89", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f077553d607adc1caf65430528a576c757a71ed73944b66ebb58ef2bbd243568" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", +] + +[[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 = "threadpool" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" +dependencies = [ + "num_cpus", +] + +[[package]] +name = "time" +version = "0.3.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +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.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" +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.41.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cfb5bee7a6a52939ca9224d6ac897bb669134078daa8735560897f69de4d33" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio 1.0.2", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.52.0", +] + +[[package]] +name = "tokio-macros" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f" +dependencies = [ + "rustls 0.22.4", + "rustls-pki-types", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" +dependencies = [ + "rustls 0.23.19", + "rustls-pki-types", + "tokio", +] + +[[package]] +name = "tokio-stream" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", + "tokio-util", +] + +[[package]] +name = "tokio-util" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[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.6.0", + "toml_datetime", + "winnow", +] + +[[package]] +name = "tower" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2873938d487c3cfb9aed7546dc9f2711d867c9f90c46b889989a2cb84eba6b4f" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper 0.1.2", + "tokio", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-http" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "403fa3b783d4b626a8ad51d766ab03cb6d2dbfc46b1c5d4448395e6628dc9697" +dependencies = [ + "bitflags 2.6.0", + "bytes", + "http", + "pin-project-lite", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.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.89", +] + +[[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-serde" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc6b213177105856957181934e4920de57730fc69bf42c37ee5bb664d406d9e1" +dependencies = [ + "serde", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "serde", + "serde_json", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", + "tracing-serde", +] + +[[package]] +name = "transcript" +version = "0.2.0" +source = "git+ssh://git@github.com/Cardinal-Cryptography/zkOS-circuits?branch=main#744505c7e4fbb615c6db46500e6d2a3b02253a6a" +dependencies = [ + "halo2_proofs", + "itertools 0.13.0", + "ruint", + "sha3 0.10.8", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "ucd-trie" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" + +[[package]] +name = "uint" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + +[[package]] +name = "unicase" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df" + +[[package]] +name = "unicode-bidi" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" + +[[package]] +name = "unicode-ident" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" + +[[package]] +name = "unicode-normalization" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + +[[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 = "url" +version = "2.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +dependencies = [ + "form_urlencoded", + "idna 1.0.3", + "percent-encoding", + "serde", +] + +[[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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wait-timeout" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" +dependencies = [ + "libc", +] + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" +dependencies = [ + "cfg-if", + "once_cell", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.89", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-rayon" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9e02b7785fe15de188657b7d3a234ef042bfd8da10822016915e06d4e29cba7" +dependencies = [ + "crossbeam-channel", + "js-sys", + "rayon", + "wasm-bindgen", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" + +[[package]] +name = "wasm_sync" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff360cade7fec41ff0e9d2cda57fe58258c5f16def0e21302394659e6bbb0ea" +dependencies = [ + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "web-sys" +version = "0.3.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" +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-roots" +version = "0.26.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d642ff16b7e79272ae451b7322067cdc17cadf68c23264be9d94a32319efe7e" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "widestring" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-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-registry" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" +dependencies = [ + "windows-result", + "windows-strings", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result", + "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.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" +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 = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[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.89", + "synstructure", +] + +[[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.89", +] + +[[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.89", + "synstructure", +] + +[[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.89", +] + +[[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.89", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 00000000..a9ea81f2 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,94 @@ +[workspace] +resolver = "2" + +members = ["crates/*"] + +[workspace.package] +edition = "2021" +authors = ["Cardinal"] +homepage = "https://alephzero.org" +license = "Apache-2.0" +categories = ["cryptography"] +repository = "https://github.com/Cardinal-Cryptography/zkOS" + +[workspace.dependencies] +alloy-contract = { version = "0.4.2" } +alloy-eips = { version = "0.4.2" } +alloy-network = { version = "0.4.2" } +alloy-primitives = { version = "0.8.5" } +alloy-provider = { version = "0.4.2" } +alloy-rpc-types = { version = "0.4.2" } +alloy-rpc-types-eth = { version = "0.4.2" } +alloy-signer = { version = "0.4.2" } +alloy-signer-local = { version = "0.4.2" } +alloy-sol-types = { version = "0.8.5" } +alloy-transport = { version = "0.4.2" } +anyhow = { version = "1.0.86", default-features = false } +askama = { version = "0.12.0", default-features = false } +async-channel = { version = "2.3.1" } +axum = { version = "0.7.7" } +byteorder = { version = "1.4.3" } +chacha20poly1305 = { version = "0.10.1", default-features = false } +clap = { version = "4.5.8" } +console_error_panic_hook = { version = "0.1.7" } +criterion = { version = "0.5.1" } +darling = { version = "0.20.10" } +getrandom = { version = "0.2" } +halo2_poseidon = { git = "ssh://git@github.com/Cardinal-Cryptography/poseidon-gadget", branch = "poseidon2-pow7" } +halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2", tag = "v0.3.0", default-features = false } +halo2curves = { version = "0.6.0", default-features = false } +hex = { version = "0.4.3" } +human_bytes = { version = "0.4.3", default-features = false } +inquire = { version = "0.7.5" } +itertools = { version = "0.13.0" } +js-sys = { version = "0.3.61" } +lazy_static = { version = "1.5.0" } +log = { version = "0.4.22" } +metrics = { version = "0.23.0", default-features = false } +metrics-exporter-prometheus = { version = "0.15.3", default-features = false } +mockall = { version = "0.13.0" } +num-bigint = { version = "0.4.3" } +once_cell = { version = "1.20.2" } +paste = { version = "1.0.15" } +proc-macro2 = { version = "1.0.86" } +quote = { version = "1.0.37" } +rand = { version = "0.8.5" } +rand_chacha = { version = "0.3.1" } +rand_core = { version = "0.6.4" } +rayon = { version = "1.8" } +reqwest = { version = "0.12.5" } +revm = { version = "14.0.3", default-features = false } +revm-interpreter = { version = "10.0.3", default-features = false } +revm-precompile = { version = "11.0.3", default-features = false } +revm-primitives = { version = "10.0.0", default-features = false } +rstest = "0.23.0" +ruint = { version = "1" } +rust-argon2 = { version = "2.1.0" } +secp256k1 = { version = "0.29.1" } +serde = { version = "1.0.203" } +serde_json = { version = "1.0.120" } +sha2 = { version = "0.10.8" } +sha3 = { version = "0.10" } +shellexpand = { version = "3.1.0" } +shielder-circuits = { git = "ssh://git@github.com/Cardinal-Cryptography/zkOS-circuits", branch = "main" } +#shielder-circuits = { path = "/home/filip/CloudStation/aleph/zkOS-circuits/crates/shielder-circuits" } +static_assertions = { version = "1.1.0" } +strum = { version = "0.26.3" } +strum_macros = { version = "0.26.3" } +syn = { version = "2.0.79" } +testcontainers = { version = "0.19.0" } +thiserror = { version = "1.0.61" } +tokio = { version = "1.38.0" } +tower-http = { version = "0.6.1" } +tracing = { version = "0.1.40" } +tracing-subscriber = { version = "0.3.18" } +wasm-bindgen = { version = "0.2.92" } +wasm-bindgen-rayon = { version = "1.2.1" } +wasm-bindgen-test = { version = "0.3.42" } + +# Local dependencies +content-encryption = { path = "crates/content-encryption", default-features = false } +evm-utils = { path = "crates/evm-utils" } +halo2_solidity_verifier = { path = "crates/halo2-verifier" } +shielder-relayer = { path = "crates/shielder-relayer" } +shielder-rust-sdk = { path = "crates/shielder-rust-sdk" } diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..9ea1b432 --- /dev/null +++ b/Makefile @@ -0,0 +1,90 @@ +NETWORK ?= anvil +PRIVATE_KEY ?= 0xb6b15c8cb491557369f3c7d2c287b053eb229daa9c22138887752191c9520659 # pkey of the dev account `0x3f1Eae7D46d88F08fc2F8ed27FCb2AB183EB2d0E` prefunded with ETH on all networks + +.PHONY: help +help: # Show help for each of the Makefile recipes. + @grep -E '^[a-zA-Z0-9 -]+:.*#' Makefile | sort | while read -r l; do printf "\033[1;32m$$(echo $$l | cut -f 1 -d':')\033[00m:$$(echo $$l | cut -f 2- -d'#')\n"; done + +.PHONY: clean +clean: # Remove all generated data +clean: + git clean -fdX + +.PHONY: deps +deps: # Install dependencies +deps: + npm install + +.PHONY: anvil +anvil: # Run local anvil node +anvil: + ./scripts/aleph-anvil.sh -p 8545 + +.PHONY: stop-anvil +stop-anvil: # Stop local anvil node +stop-anvil: + pkill anvil + +.PHONY: watch-contracts +watch-contracts: # watcher on the eth contracts. Scripts dir is watched by default +watch-contracts: + forge build --watch contracts/*.sol --watch scripts/*.sol + +.PHONY: format-contracts +format-contracts: # Format solidity contracts +format-contracts: + npx prettier --write --plugin=prettier-plugin-solidity 'contracts/*.sol' 'scripts/*.sol' + +.PHONY: lint-contracts +lint-contracts: # Lint solidity contracts +lint-contracts: + npx solhint -c .solhint.json 'contracts/*.sol' 'scripts/*.sol' + +.PHONY: compile-contracts +compile-contracts: # Compile solidity contracts +compile-contracts: generate-verifier-contracts + forge build + +.PHONY: deploy-contracts +deploy-contracts: # Deploy solidity contracts +deploy-contracts: +ifeq ($(NETWORK),anvil) + PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 forge script DeployShielderScript --broadcast --rpc-url anvil +else + PRIVATE_KEY=$(PRIVATE_KEY) forge script DeployShielderScript --broadcast --rpc-url $(NETWORK) +endif + +.PHONY: generate-poseidon-contracts +generate-poseidon-contracts: # Generate Poseidon contract +generate-poseidon-contracts: + python3 poseidon2-solidity/generate_t8.py > contracts/Poseidon2T8Assembly.sol + npx prettier --write --plugin=prettier-plugin-solidity 'contracts/Poseidon2T*Assembly.sol' + +.PHONY: generate-verifier-contracts +generate-verifier-contracts: # Generate relation verifier contracts +generate-verifier-contracts: + cd crates/halo2-verifier + cargo run --release --bin halo2_solidity_verifier_generator + $(MAKE) format-contracts + +.PHONY: format-rust +format-rust: # Format all rust crates +format-rust: + cargo +nightly fmt --all -- --check + +.PHONY: lint-rust +lint-rust: # Lint all rust crates +lint-rust: + cargo clippy --release -- -D warnings + +.PHONY: generate-tooling-dev +generate-tooling-dev: # Generate tooling-dev package +generate-tooling-dev: + cp tooling-e2e-tests/local_env.sh tooling-dev/ + cp crates/shielder-relayer/run-relayer.sh tooling-dev/ + cp package.json tooling-dev/ + cp package-lock.json tooling-dev/ + cp foundry.toml tooling-dev/ + cp -r contracts tooling-dev/ + cp -r scripts tooling-dev/ + git rev-parse --short=7 HEAD > tooling-dev/.git-sha diff --git a/README.md b/README.md new file mode 100644 index 00000000..a1510d2e --- /dev/null +++ b/README.md @@ -0,0 +1,90 @@ +[![LOGO][logo]][aleph-homepage] + +[![Test suite][tests-badge]][tests] +[![Nightly Testnet E2E tests][nightly-tests-badge]][nightly-tests] + +# Shielder: A First Iteration of zkOS + +Welcome to Shielder, the first iteration of zkOS by Aleph Zero. +Shielder is designed to provide a seamless integration of zero-knowledge (ZK) privacy into Ethereum Virtual Machine (EVM) compatible environments with subsecond proving times. + +## Table of Contents + +- [Introduction](#introduction) +- [Features](#features) +- [Architecture](#architecture) +- [Getting Started](#getting-started) + - [Prerequisites](#prerequisites) + - [Usage](#usage) +- [License](#license) + +## Introduction + +Shielder is part of the Aleph Zero zkOS initiative, aimed at delivering Privacy-as-a-Service for Web3. With zkOS, developers can integrate ZK-based privacy into their applications without deep cryptographic knowledge. + +## Features + +- **EVM Compatibility**: Easily integrate with existing Ethereum-based applications. +- **Subsecond Proving**: Achieve zero-knowledge proofs in 600-800 ms on standard hardware. +- **High Performance**: Supports up to 250ms block time and processes thousands of transactions per second. +- **Developer-Friendly**: Comprehensive tooling and frameworks to simplify integration. +- **Privacy-Enhanced**: Build and deploy privacy-enhanced applications effortlessly. + +# Architecture + +Shielder is built utilizing the following components: + +- **Aleph Zero WASM L1**: Serves as the Data Availability layer. +- **EVM Layer 2 Rollup**: Leverages Arbitrum Anytrust DAC technology for fast and secure execution. +- **Developer Tooling**: Includes Gelato’s web3 services, account abstraction, functions, VRF, oracles, block explorers, indexers, and multisig support. + +## Getting Started + +### Prerequisites + +Before you begin, ensure you have the following: + +- Node.js and npm installed +- Docker (optional, for containerized deployment) +- An Ethereum wallet + +### Usage + +Clone the repository and install the dependencies: + +```bash +git clone git@github.com:Cardinal-Cryptography/zkOS.git +cd zkOS +make deps +``` + +Boot a local node: + +```bash +make anvil +``` + +Compile & deploy the smart contract suite: + +```bash +make deploy-contracts +``` + +### Deploying to anvil + +The command below will use `0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266` as a deployer: + +```bash +NETWORK=anvil make deploy-contracts +``` + +## License + +Shielder is licensed under the MIT License. See the LICENSE file for more details. + +[aleph-homepage]: https://alephzero.org +[logo]: logo.png +[tests]: https://github.com/Cardinal-Cryptography/zkOS-monorepo/actions/workflows/on-master-branch-push-pull_request.yml +[tests-badge]: https://github.com/Cardinal-Cryptography/zkOS-monorepo/actions/workflows/on-master-branch-push-pull_request.yml/badge.svg +[nightly-tests]: https://github.com/Cardinal-Cryptography/zkOS-monorepo/actions/workflows/nightly-testnet-e2e.yml +[nightly-tests-badge]: https://github.com/Cardinal-Cryptography/zkOS-monorepo/actions/workflows/nightly-testnet-e2e.yml/badge.svg diff --git a/contracts/ArbSysMock.sol b/contracts/ArbSysMock.sol new file mode 100644 index 00000000..4785bb4a --- /dev/null +++ b/contracts/ArbSysMock.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import { IArbSys } from "./IArbSys.sol"; + +/** + * Mock implementation of ArbSys for testing purposes. + * @dev Returns just the `block.number`. Will work well when run on L1 chain. + */ +contract ArbSysMock is IArbSys { + /** + * @notice Get Arbitrum block number + * @return block number as uint256 + */ + function arbBlockNumber() external view override returns (uint256) { + return block.number; + } +} diff --git a/contracts/IArbSys.sol b/contracts/IArbSys.sol new file mode 100644 index 00000000..fb94c591 --- /dev/null +++ b/contracts/IArbSys.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.14; + +// Interface taken from https://docs.arbitrum.io/build-decentralized-apps/precompiles/reference#arbsys. + +/** + * @title System level functionality + * @notice For use by contracts to interact with core L2-specific functionality. + * Precompiled contract that exists in every Arbitrum chain at address(100), 0x0000000000000000000000000000000000000064. + */ +interface IArbSys { + /** + * @notice Get Arbitrum block number (distinct from L1 block number; Arbitrum genesis block has block number 0) + * @return block number as uint256 + */ + function arbBlockNumber() external view returns (uint256); +} diff --git a/contracts/MerkleTree.sol b/contracts/MerkleTree.sol new file mode 100644 index 00000000..a8dd6200 --- /dev/null +++ b/contracts/MerkleTree.sol @@ -0,0 +1,144 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.26; +import { Math } from "@openzeppelin/contracts/utils/math/Math.sol"; +import { Poseidon2T8Assembly as Poseidon2 } from "./Poseidon2T8Assembly.sol"; + +/* + * Merkle Tree with Poseidon2 + */ + +library MerkleTree { + uint256 public constant ARITY = 7; + uint256 public constant TREE_HEIGHT = 13; + // tree height is computed as ceil(log_{ARITY}(2^36)) + + struct MerkleTreeData { + mapping(uint256 => uint256) notes; + uint256 root; + uint256 nextFreeLeafId; + uint256 maxLeafId; + uint256 firstLeafId; + } + + error InvalidTreeHeight(); + error MaxTreeSizeExceeded(); + error LeafNotExisting(); + + /* + * Initialize the tree. + */ + function init(MerkleTreeData storage merkleTree) internal { + (merkleTree.maxLeafId, merkleTree.nextFreeLeafId) = treeBounds( + TREE_HEIGHT + ); + merkleTree.firstLeafId = merkleTree.nextFreeLeafId; + } + + /* + * Add a note to the tree. + * Returns the index of the note in the tree starting from 0. + * If the tree is full, it will revert. + */ + function addNote( + MerkleTreeData storage self, + uint256 note + ) internal returns (uint256) { + if (self.nextFreeLeafId > self.maxLeafId) revert MaxTreeSizeExceeded(); + + uint256 index = self.nextFreeLeafId; + uint256 parent = 0; + uint256[ARITY] memory subtrees; + self.notes[index] = note; + + for (uint256 i = 0; i < TREE_HEIGHT; ) { + unchecked { + parent = (index + ARITY - 2) / ARITY; + } + for (uint256 j = 0; j < ARITY; ) { + subtrees[j] = self.notes[parent * ARITY + j - (ARITY - 2)]; + unchecked { + j++; + } + } + note = Poseidon2.hash(subtrees); + self.notes[parent] = note; + + index = parent; + unchecked { + i++; + } + } + self.root = note; + self.nextFreeLeafId += 1; + + return self.nextFreeLeafId - self.firstLeafId - 1; + } + + /* + * Given an index of a leaf return the path from a leaf index to the root. + * Leaves are indexed from 0. + * Path is an array of length TREE_HEIGHT*ARITY+1, where the first TREE_HEIGHT*ARITY elements are the siblings of the path, + * and the last element is the root. + * If tree looks like this: + * l_3 = hash(l_1, l_2) + * l_5 = hash(l_3, l_4) + * ... + * root = hash(l_71, l_72) + * Then the path for l_1 is: + * | l_1 l_2 | l_3 l_4 | l_5 l_6 | ... | l_71 l_72 | root | + */ + function getMerklePath( + MerkleTreeData storage self, + uint256 index + ) internal view returns (uint256[] memory) { + if (index >= self.nextFreeLeafId - self.firstLeafId) { + revert LeafNotExisting(); + } + index += self.firstLeafId; + + uint256[] memory path = new uint256[](TREE_HEIGHT * ARITY + 1); + + uint256 parent = 0; + for (uint256 i = 0; i < TREE_HEIGHT; ) { + unchecked { + parent = (index + ARITY - 2) / ARITY; + } + for (uint256 j = 0; j < ARITY; ) { + path[i * ARITY + j] = self.notes[ + parent * ARITY + j - (ARITY - 2) + ]; + unchecked { + j++; + } + } + + index = parent; + unchecked { + i++; + } + } + path[TREE_HEIGHT * ARITY] = self.root; + + return path; + } + + /* + * Given a tree height, return the maximum index of a leaf and the index of the first leaf. + * Throw an error if height is too big. + */ + function treeBounds( + uint256 treeHeight + ) private pure returns (uint256, uint256) { + uint256 size = 1; + uint256 power = 1; + bool flag = true; + for (uint256 i = 1; i <= treeHeight; i++) { + (flag, power) = Math.tryMul(power, ARITY); + if (!flag) revert InvalidTreeHeight(); + (flag, size) = Math.tryAdd(size, power); + if (!flag) revert InvalidTreeHeight(); + } + return (size, size - power + 1); + } +} diff --git a/contracts/Permit2.sol b/contracts/Permit2.sol new file mode 100644 index 00000000..ed2e1140 --- /dev/null +++ b/contracts/Permit2.sol @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.14; + +/* @dev: needed to compile Permit2 */ +/* solhint-disable no-unused-import */ +import { Permit2 } from "@uniswap/permit2/src/Permit2.sol"; diff --git a/contracts/Poseidon2T8Assembly.sol b/contracts/Poseidon2T8Assembly.sol new file mode 100644 index 00000000..e647f133 --- /dev/null +++ b/contracts/Poseidon2T8Assembly.sol @@ -0,0 +1,6682 @@ +pragma solidity 0.8.26; +library Poseidon2T8Assembly { + function hash(uint256[7] memory) public pure returns (uint256) { + assembly { + function sum() { + mstore( + 0x140, + addmod( + add( + addmod( + add( + mload(0x00), + add( + mload(0x20), + add( + mload(0x80), + add(mload(0xa0), mload(0xc0)) + ) + ) + ), + mload(0xe0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x100) + ), + mload(0x120), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + function mm4(a, b, c, d) { + let t0 := add(mload(a), mload(b)) // a + b + let t1 := add(mload(c), mload(d)) // + c + d + let t2 := add(mload(b), add(mload(b), t1)) // + 2b + c + d + let t3 := add(mload(d), add(mload(d), t0)) // a + b + 2d + let t4 := add(t1, t1) // 2c + 2d + t4 := addmod( + t4, + t4, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) // 4c + 4d + t4 := addmod( + t4, + t3, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) // a + b + 4c + 6d + let t5 := add(t0, t0) // 2a + 2b + t5 := addmod( + t5, + t5, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) // 4a + 4b + t5 := addmod( + t5, + t2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) // 4a + 6b + c + d + + mstore( + a, + addmod( + t3, + t5, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore(b, t5) + mstore( + c, + addmod( + t2, + t4, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore(d, t4) + } + + function fr_mm() { + mm4(0x00, 0x20, 0x80, 0xa0) + mm4(0xc0, 0xe0, 0x100, 0x120) + + mstore(0x140, add(mload(0x00), mload(0xc0))) + mstore(0x160, add(mload(0x20), mload(0xe0))) + mstore(0x180, add(mload(0x80), mload(0x100))) + mstore(0x1a0, add(mload(0xa0), mload(0x120))) + + mstore( + 0x00, + addmod( + mload(0x00), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x20, + addmod( + mload(0x20), + mload(0x160), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x80, + addmod( + mload(0x80), + mload(0x180), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xa0, + addmod( + mload(0xa0), + mload(0x1a0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xc0, + addmod( + mload(0xc0), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xe0, + addmod( + mload(0xe0), + mload(0x160), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x100, + addmod( + mload(0x100), + mload(0x180), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x120, + addmod( + mload(0x120), + mload(0x1a0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + function fr_intro(c0, c1, c2, c3, c4, c5, c6, c7) { + let state0 := add(mload(0x00), c0) + { + let var2 := mulmod( + state0, + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + let var4 := mulmod( + var2, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + mstore( + 0x00, + mulmod( + mulmod( + var4, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + let state1 := add(mload(0x20), c1) + { + let var2 := mulmod( + state1, + state1, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + let var4 := mulmod( + var2, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + mstore( + 0x20, + mulmod( + mulmod( + var4, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + state1, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + let state2 := add(mload(0x80), c2) + { + let var2 := mulmod( + state2, + state2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + let var4 := mulmod( + var2, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + mstore( + 0x80, + mulmod( + mulmod( + var4, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + state2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + let state3 := add(mload(0xa0), c3) + { + let var2 := mulmod( + state3, + state3, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + let var4 := mulmod( + var2, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + mstore( + 0xa0, + mulmod( + mulmod( + var4, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + state3, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + let state4 := add(mload(0xc0), c4) + { + let var2 := mulmod( + state4, + state4, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + let var4 := mulmod( + var2, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + mstore( + 0xc0, + mulmod( + mulmod( + var4, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + state4, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + let state5 := add(mload(0xe0), c5) + { + let var2 := mulmod( + state5, + state5, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + let var4 := mulmod( + var2, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + mstore( + 0xe0, + mulmod( + mulmod( + var4, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + state5, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + let state6 := add(mload(0x100), c6) + { + let var2 := mulmod( + state6, + state6, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + let var4 := mulmod( + var2, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + mstore( + 0x100, + mulmod( + mulmod( + var4, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + state6, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + let state7 := add(mload(0x120), c7) + { + let var2 := mulmod( + state7, + state7, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + let var4 := mulmod( + var2, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + mstore( + 0x120, + mulmod( + mulmod( + var4, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + state7, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + } + + mstore(0x00, mload(0x080)) + mstore(0x20, mload(0x0a0)) + mstore(0x80, mload(0x0c0)) + mstore(0xa0, mload(0x0e0)) + mstore(0xc0, mload(0x100)) + mstore(0xe0, mload(0x120)) + mstore(0x100, mload(0x140)) + mstore(0x120, 129127208515966861312) + + fr_mm() + + { + fr_intro( + 4374910847496570502851666885419112453902517339857936546642776148093208834076, + 4043213966675802222711951833799747398544826675171104649923510397774605701432, + 10295457532979908351689870330273304172034280885513669796993861960192447770433, + 13185549805193951237530306688380766158835192431473268775288108542040064983071, + 13031669968593716420209817549905011043748303215734206479455307665118481917735, + 18343454766307691225698897877005276380323314575088714109848555232962927806451, + 4285598628460968749045653380268362330101985063701482288209687847531702020142, + 6396360754966367114418673553740502687780213591488826781874722869496104602554 + ) + fr_mm() + } + + { + fr_intro( + 16200804545643582389651312275787196022923363607710794506797044233734656121044, + 5134113862164183256837156309894643041635561742417093535155792168400431031128, + 16471262385794041608522265868619559042749216664461639171092582570120233458738, + 15723793949959091386062587647943267657651324687857644398097267442086421222837, + 4446608623965585589069696696206788262733768624291356886053262391248913164030, + 12263662121776110063124264291823110630103516514597816100285412992928428141693, + 13727309801509560416443333055765002796184618911221393457056781958666764100492, + 12035506540047119988708392579833344597280695956718584325712108831864228117468 + ) + fr_mm() + } + + { + fr_intro( + 2137349817265832389630431403020686625284455384467896815597687377494641047396, + 4748593344659988252042998947010556624672186775256478994223811901919391329801, + 3877706675344496756243474607993753102537735202197057886890771729592494656346, + 15647915819346078484784806320063471126994550702265590557961181419988789965763, + 14405905899560914295870617237758358277304043621193837463463843094804092059239, + 14784694522234549653759635058994355941926443631841664622096500140484558680685, + 18899741568972126096340573504141014616014744452536151726719977363015788770512, + 5451313876118173933795880888264229902146494327637141336196058929430726660258 + ) + fr_mm() + } + + { + fr_intro( + 8523490007889545992873929078045575160693040385939070075958015007341678815377, + 17290246629648536472352733006841342309105450862473341949043067707842479341967, + 14700591146031062723163899911366439421207304211867736420137668775953124921184, + 19913634027676989763433084135421222826701272045849433405013103499081618365783, + 3259437893706969557036945674914639947393447161093753975815625697652910191444, + 16969164682773159039689327973436447588570424605015123874750285193369165651709, + 14824538783460991003207046836693352460422165588686218795092602237388721955441, + 12294108935004528953312621254245550647064707709668192842054169419944743387026 + ) + fr_mm() + } + + { + let state0 := add( + mload(0x00), + 17887213884740404694263669711691166469270926080573489933611199178426226025621 + ) + { + let var2 := mulmod( + state0, + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + let var4 := mulmod( + var2, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + mstore( + 0x00, + mulmod( + mulmod( + var4, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + sum() + mstore( + 0x00, + addmod( + mulmod( + 2600766909924179814780409961696866414079699656430070499803459729017893381997, + mload(0x00), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x20, + addmod( + mulmod( + 19293363242678774625215171492393209093707286181479006293654394057747218353607, + mload(0x20), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x80, + addmod( + mulmod( + 21414786808156610356356451480905960406647514095406216853368573063004475600640, + mload(0x80), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xa0, + addmod( + mulmod( + 8215135898581116354906741804378477022438799156627805573019887031189487620936, + mload(0xa0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xc0, + addmod( + mulmod( + 9165814748476180913577766403125055556952884368727238651703828504915350029819, + mload(0xc0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xe0, + addmod( + mulmod( + 15078459252378813527385228808553999657222567675360137586804698725603240352055, + mload(0xe0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x100, + addmod( + mulmod( + 5648186893216350474836221186116590993767413676065426352255299742021094533501, + mload(0x100), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x120, + addmod( + mulmod( + 20725344080263893594397636575905698660034655258256134536883719628954264697683, + mload(0x120), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + { + let state0 := add( + mload(0x00), + 8384861720264271278572752935970765586580871388412738840337100629527015944091 + ) + { + let var2 := mulmod( + state0, + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + let var4 := mulmod( + var2, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + mstore( + 0x00, + mulmod( + mulmod( + var4, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + sum() + mstore( + 0x00, + addmod( + mulmod( + 2600766909924179814780409961696866414079699656430070499803459729017893381997, + mload(0x00), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x20, + addmod( + mulmod( + 19293363242678774625215171492393209093707286181479006293654394057747218353607, + mload(0x20), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x80, + addmod( + mulmod( + 21414786808156610356356451480905960406647514095406216853368573063004475600640, + mload(0x80), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xa0, + addmod( + mulmod( + 8215135898581116354906741804378477022438799156627805573019887031189487620936, + mload(0xa0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xc0, + addmod( + mulmod( + 9165814748476180913577766403125055556952884368727238651703828504915350029819, + mload(0xc0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xe0, + addmod( + mulmod( + 15078459252378813527385228808553999657222567675360137586804698725603240352055, + mload(0xe0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x100, + addmod( + mulmod( + 5648186893216350474836221186116590993767413676065426352255299742021094533501, + mload(0x100), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x120, + addmod( + mulmod( + 20725344080263893594397636575905698660034655258256134536883719628954264697683, + mload(0x120), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + { + let state0 := add( + mload(0x00), + 11415188990977796463133969050582766732114945674183269184380896042912135094257 + ) + { + let var2 := mulmod( + state0, + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + let var4 := mulmod( + var2, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + mstore( + 0x00, + mulmod( + mulmod( + var4, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + sum() + mstore( + 0x00, + addmod( + mulmod( + 2600766909924179814780409961696866414079699656430070499803459729017893381997, + mload(0x00), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x20, + addmod( + mulmod( + 19293363242678774625215171492393209093707286181479006293654394057747218353607, + mload(0x20), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x80, + addmod( + mulmod( + 21414786808156610356356451480905960406647514095406216853368573063004475600640, + mload(0x80), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xa0, + addmod( + mulmod( + 8215135898581116354906741804378477022438799156627805573019887031189487620936, + mload(0xa0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xc0, + addmod( + mulmod( + 9165814748476180913577766403125055556952884368727238651703828504915350029819, + mload(0xc0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xe0, + addmod( + mulmod( + 15078459252378813527385228808553999657222567675360137586804698725603240352055, + mload(0xe0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x100, + addmod( + mulmod( + 5648186893216350474836221186116590993767413676065426352255299742021094533501, + mload(0x100), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x120, + addmod( + mulmod( + 20725344080263893594397636575905698660034655258256134536883719628954264697683, + mload(0x120), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + { + let state0 := add( + mload(0x00), + 4043439830090880176534002167931353039116821897062471893640429781805068860710 + ) + { + let var2 := mulmod( + state0, + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + let var4 := mulmod( + var2, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + mstore( + 0x00, + mulmod( + mulmod( + var4, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + sum() + mstore( + 0x00, + addmod( + mulmod( + 2600766909924179814780409961696866414079699656430070499803459729017893381997, + mload(0x00), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x20, + addmod( + mulmod( + 19293363242678774625215171492393209093707286181479006293654394057747218353607, + mload(0x20), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x80, + addmod( + mulmod( + 21414786808156610356356451480905960406647514095406216853368573063004475600640, + mload(0x80), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xa0, + addmod( + mulmod( + 8215135898581116354906741804378477022438799156627805573019887031189487620936, + mload(0xa0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xc0, + addmod( + mulmod( + 9165814748476180913577766403125055556952884368727238651703828504915350029819, + mload(0xc0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xe0, + addmod( + mulmod( + 15078459252378813527385228808553999657222567675360137586804698725603240352055, + mload(0xe0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x100, + addmod( + mulmod( + 5648186893216350474836221186116590993767413676065426352255299742021094533501, + mload(0x100), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x120, + addmod( + mulmod( + 20725344080263893594397636575905698660034655258256134536883719628954264697683, + mload(0x120), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + { + let state0 := add( + mload(0x00), + 3285981043091489096090035052889181959379926235192733497560048442282261344163 + ) + { + let var2 := mulmod( + state0, + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + let var4 := mulmod( + var2, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + mstore( + 0x00, + mulmod( + mulmod( + var4, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + sum() + mstore( + 0x00, + addmod( + mulmod( + 2600766909924179814780409961696866414079699656430070499803459729017893381997, + mload(0x00), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x20, + addmod( + mulmod( + 19293363242678774625215171492393209093707286181479006293654394057747218353607, + mload(0x20), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x80, + addmod( + mulmod( + 21414786808156610356356451480905960406647514095406216853368573063004475600640, + mload(0x80), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xa0, + addmod( + mulmod( + 8215135898581116354906741804378477022438799156627805573019887031189487620936, + mload(0xa0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xc0, + addmod( + mulmod( + 9165814748476180913577766403125055556952884368727238651703828504915350029819, + mload(0xc0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xe0, + addmod( + mulmod( + 15078459252378813527385228808553999657222567675360137586804698725603240352055, + mload(0xe0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x100, + addmod( + mulmod( + 5648186893216350474836221186116590993767413676065426352255299742021094533501, + mload(0x100), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x120, + addmod( + mulmod( + 20725344080263893594397636575905698660034655258256134536883719628954264697683, + mload(0x120), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + { + let state0 := add( + mload(0x00), + 5089720679132371154943614112997133982140084176544464385571738300063187139498 + ) + { + let var2 := mulmod( + state0, + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + let var4 := mulmod( + var2, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + mstore( + 0x00, + mulmod( + mulmod( + var4, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + sum() + mstore( + 0x00, + addmod( + mulmod( + 2600766909924179814780409961696866414079699656430070499803459729017893381997, + mload(0x00), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x20, + addmod( + mulmod( + 19293363242678774625215171492393209093707286181479006293654394057747218353607, + mload(0x20), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x80, + addmod( + mulmod( + 21414786808156610356356451480905960406647514095406216853368573063004475600640, + mload(0x80), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xa0, + addmod( + mulmod( + 8215135898581116354906741804378477022438799156627805573019887031189487620936, + mload(0xa0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xc0, + addmod( + mulmod( + 9165814748476180913577766403125055556952884368727238651703828504915350029819, + mload(0xc0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xe0, + addmod( + mulmod( + 15078459252378813527385228808553999657222567675360137586804698725603240352055, + mload(0xe0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x100, + addmod( + mulmod( + 5648186893216350474836221186116590993767413676065426352255299742021094533501, + mload(0x100), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x120, + addmod( + mulmod( + 20725344080263893594397636575905698660034655258256134536883719628954264697683, + mload(0x120), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + { + let state0 := add( + mload(0x00), + 18113881451258125168676724071576339869643904892995107435540258593798179700430 + ) + { + let var2 := mulmod( + state0, + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + let var4 := mulmod( + var2, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + mstore( + 0x00, + mulmod( + mulmod( + var4, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + sum() + mstore( + 0x00, + addmod( + mulmod( + 2600766909924179814780409961696866414079699656430070499803459729017893381997, + mload(0x00), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x20, + addmod( + mulmod( + 19293363242678774625215171492393209093707286181479006293654394057747218353607, + mload(0x20), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x80, + addmod( + mulmod( + 21414786808156610356356451480905960406647514095406216853368573063004475600640, + mload(0x80), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xa0, + addmod( + mulmod( + 8215135898581116354906741804378477022438799156627805573019887031189487620936, + mload(0xa0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xc0, + addmod( + mulmod( + 9165814748476180913577766403125055556952884368727238651703828504915350029819, + mload(0xc0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xe0, + addmod( + mulmod( + 15078459252378813527385228808553999657222567675360137586804698725603240352055, + mload(0xe0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x100, + addmod( + mulmod( + 5648186893216350474836221186116590993767413676065426352255299742021094533501, + mload(0x100), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x120, + addmod( + mulmod( + 20725344080263893594397636575905698660034655258256134536883719628954264697683, + mload(0x120), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + { + let state0 := add( + mload(0x00), + 17035511805914875958405421138030015099427303400596998407886140379590312329958 + ) + { + let var2 := mulmod( + state0, + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + let var4 := mulmod( + var2, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + mstore( + 0x00, + mulmod( + mulmod( + var4, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + sum() + mstore( + 0x00, + addmod( + mulmod( + 2600766909924179814780409961696866414079699656430070499803459729017893381997, + mload(0x00), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x20, + addmod( + mulmod( + 19293363242678774625215171492393209093707286181479006293654394057747218353607, + mload(0x20), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x80, + addmod( + mulmod( + 21414786808156610356356451480905960406647514095406216853368573063004475600640, + mload(0x80), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xa0, + addmod( + mulmod( + 8215135898581116354906741804378477022438799156627805573019887031189487620936, + mload(0xa0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xc0, + addmod( + mulmod( + 9165814748476180913577766403125055556952884368727238651703828504915350029819, + mload(0xc0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xe0, + addmod( + mulmod( + 15078459252378813527385228808553999657222567675360137586804698725603240352055, + mload(0xe0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x100, + addmod( + mulmod( + 5648186893216350474836221186116590993767413676065426352255299742021094533501, + mload(0x100), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x120, + addmod( + mulmod( + 20725344080263893594397636575905698660034655258256134536883719628954264697683, + mload(0x120), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + { + let state0 := add( + mload(0x00), + 3390797776612057923683522652529910602151366267475587231965343130960981907120 + ) + { + let var2 := mulmod( + state0, + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + let var4 := mulmod( + var2, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + mstore( + 0x00, + mulmod( + mulmod( + var4, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + sum() + mstore( + 0x00, + addmod( + mulmod( + 2600766909924179814780409961696866414079699656430070499803459729017893381997, + mload(0x00), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x20, + addmod( + mulmod( + 19293363242678774625215171492393209093707286181479006293654394057747218353607, + mload(0x20), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x80, + addmod( + mulmod( + 21414786808156610356356451480905960406647514095406216853368573063004475600640, + mload(0x80), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xa0, + addmod( + mulmod( + 8215135898581116354906741804378477022438799156627805573019887031189487620936, + mload(0xa0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xc0, + addmod( + mulmod( + 9165814748476180913577766403125055556952884368727238651703828504915350029819, + mload(0xc0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xe0, + addmod( + mulmod( + 15078459252378813527385228808553999657222567675360137586804698725603240352055, + mload(0xe0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x100, + addmod( + mulmod( + 5648186893216350474836221186116590993767413676065426352255299742021094533501, + mload(0x100), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x120, + addmod( + mulmod( + 20725344080263893594397636575905698660034655258256134536883719628954264697683, + mload(0x120), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + { + let state0 := add( + mload(0x00), + 15950158835044687249587788527739740324819281225343680355516183812452457910587 + ) + { + let var2 := mulmod( + state0, + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + let var4 := mulmod( + var2, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + mstore( + 0x00, + mulmod( + mulmod( + var4, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + sum() + mstore( + 0x00, + addmod( + mulmod( + 2600766909924179814780409961696866414079699656430070499803459729017893381997, + mload(0x00), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x20, + addmod( + mulmod( + 19293363242678774625215171492393209093707286181479006293654394057747218353607, + mload(0x20), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x80, + addmod( + mulmod( + 21414786808156610356356451480905960406647514095406216853368573063004475600640, + mload(0x80), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xa0, + addmod( + mulmod( + 8215135898581116354906741804378477022438799156627805573019887031189487620936, + mload(0xa0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xc0, + addmod( + mulmod( + 9165814748476180913577766403125055556952884368727238651703828504915350029819, + mload(0xc0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xe0, + addmod( + mulmod( + 15078459252378813527385228808553999657222567675360137586804698725603240352055, + mload(0xe0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x100, + addmod( + mulmod( + 5648186893216350474836221186116590993767413676065426352255299742021094533501, + mload(0x100), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x120, + addmod( + mulmod( + 20725344080263893594397636575905698660034655258256134536883719628954264697683, + mload(0x120), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + { + let state0 := add( + mload(0x00), + 13095279455455100007770712355994786378159656575937178414750768529430123074327 + ) + { + let var2 := mulmod( + state0, + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + let var4 := mulmod( + var2, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + mstore( + 0x00, + mulmod( + mulmod( + var4, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + sum() + mstore( + 0x00, + addmod( + mulmod( + 2600766909924179814780409961696866414079699656430070499803459729017893381997, + mload(0x00), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x20, + addmod( + mulmod( + 19293363242678774625215171492393209093707286181479006293654394057747218353607, + mload(0x20), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x80, + addmod( + mulmod( + 21414786808156610356356451480905960406647514095406216853368573063004475600640, + mload(0x80), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xa0, + addmod( + mulmod( + 8215135898581116354906741804378477022438799156627805573019887031189487620936, + mload(0xa0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xc0, + addmod( + mulmod( + 9165814748476180913577766403125055556952884368727238651703828504915350029819, + mload(0xc0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xe0, + addmod( + mulmod( + 15078459252378813527385228808553999657222567675360137586804698725603240352055, + mload(0xe0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x100, + addmod( + mulmod( + 5648186893216350474836221186116590993767413676065426352255299742021094533501, + mload(0x100), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x120, + addmod( + mulmod( + 20725344080263893594397636575905698660034655258256134536883719628954264697683, + mload(0x120), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + { + let state0 := add( + mload(0x00), + 15072002081519380677842256312524244159989959621223774105455889608327077539930 + ) + { + let var2 := mulmod( + state0, + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + let var4 := mulmod( + var2, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + mstore( + 0x00, + mulmod( + mulmod( + var4, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + sum() + mstore( + 0x00, + addmod( + mulmod( + 2600766909924179814780409961696866414079699656430070499803459729017893381997, + mload(0x00), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x20, + addmod( + mulmod( + 19293363242678774625215171492393209093707286181479006293654394057747218353607, + mload(0x20), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x80, + addmod( + mulmod( + 21414786808156610356356451480905960406647514095406216853368573063004475600640, + mload(0x80), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xa0, + addmod( + mulmod( + 8215135898581116354906741804378477022438799156627805573019887031189487620936, + mload(0xa0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xc0, + addmod( + mulmod( + 9165814748476180913577766403125055556952884368727238651703828504915350029819, + mload(0xc0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xe0, + addmod( + mulmod( + 15078459252378813527385228808553999657222567675360137586804698725603240352055, + mload(0xe0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x100, + addmod( + mulmod( + 5648186893216350474836221186116590993767413676065426352255299742021094533501, + mload(0x100), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x120, + addmod( + mulmod( + 20725344080263893594397636575905698660034655258256134536883719628954264697683, + mload(0x120), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + { + let state0 := add( + mload(0x00), + 5023362554662599501385121542720837333112880828506514763527520994117003013587 + ) + { + let var2 := mulmod( + state0, + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + let var4 := mulmod( + var2, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + mstore( + 0x00, + mulmod( + mulmod( + var4, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + sum() + mstore( + 0x00, + addmod( + mulmod( + 2600766909924179814780409961696866414079699656430070499803459729017893381997, + mload(0x00), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x20, + addmod( + mulmod( + 19293363242678774625215171492393209093707286181479006293654394057747218353607, + mload(0x20), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x80, + addmod( + mulmod( + 21414786808156610356356451480905960406647514095406216853368573063004475600640, + mload(0x80), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xa0, + addmod( + mulmod( + 8215135898581116354906741804378477022438799156627805573019887031189487620936, + mload(0xa0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xc0, + addmod( + mulmod( + 9165814748476180913577766403125055556952884368727238651703828504915350029819, + mload(0xc0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xe0, + addmod( + mulmod( + 15078459252378813527385228808553999657222567675360137586804698725603240352055, + mload(0xe0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x100, + addmod( + mulmod( + 5648186893216350474836221186116590993767413676065426352255299742021094533501, + mload(0x100), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x120, + addmod( + mulmod( + 20725344080263893594397636575905698660034655258256134536883719628954264697683, + mload(0x120), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + { + let state0 := add( + mload(0x00), + 6319655669922293228547410028634618999888313728892929946601369734256669569212 + ) + { + let var2 := mulmod( + state0, + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + let var4 := mulmod( + var2, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + mstore( + 0x00, + mulmod( + mulmod( + var4, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + sum() + mstore( + 0x00, + addmod( + mulmod( + 2600766909924179814780409961696866414079699656430070499803459729017893381997, + mload(0x00), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x20, + addmod( + mulmod( + 19293363242678774625215171492393209093707286181479006293654394057747218353607, + mload(0x20), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x80, + addmod( + mulmod( + 21414786808156610356356451480905960406647514095406216853368573063004475600640, + mload(0x80), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xa0, + addmod( + mulmod( + 8215135898581116354906741804378477022438799156627805573019887031189487620936, + mload(0xa0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xc0, + addmod( + mulmod( + 9165814748476180913577766403125055556952884368727238651703828504915350029819, + mload(0xc0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xe0, + addmod( + mulmod( + 15078459252378813527385228808553999657222567675360137586804698725603240352055, + mload(0xe0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x100, + addmod( + mulmod( + 5648186893216350474836221186116590993767413676065426352255299742021094533501, + mload(0x100), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x120, + addmod( + mulmod( + 20725344080263893594397636575905698660034655258256134536883719628954264697683, + mload(0x120), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + { + let state0 := add( + mload(0x00), + 18607917525751184282734424082901458732437701986685218970961235088620428347046 + ) + { + let var2 := mulmod( + state0, + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + let var4 := mulmod( + var2, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + mstore( + 0x00, + mulmod( + mulmod( + var4, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + sum() + mstore( + 0x00, + addmod( + mulmod( + 2600766909924179814780409961696866414079699656430070499803459729017893381997, + mload(0x00), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x20, + addmod( + mulmod( + 19293363242678774625215171492393209093707286181479006293654394057747218353607, + mload(0x20), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x80, + addmod( + mulmod( + 21414786808156610356356451480905960406647514095406216853368573063004475600640, + mload(0x80), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xa0, + addmod( + mulmod( + 8215135898581116354906741804378477022438799156627805573019887031189487620936, + mload(0xa0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xc0, + addmod( + mulmod( + 9165814748476180913577766403125055556952884368727238651703828504915350029819, + mload(0xc0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xe0, + addmod( + mulmod( + 15078459252378813527385228808553999657222567675360137586804698725603240352055, + mload(0xe0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x100, + addmod( + mulmod( + 5648186893216350474836221186116590993767413676065426352255299742021094533501, + mload(0x100), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x120, + addmod( + mulmod( + 20725344080263893594397636575905698660034655258256134536883719628954264697683, + mload(0x120), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + { + let state0 := add( + mload(0x00), + 19286195190293133769283845732974176141991008935236887811137271481948236719579 + ) + { + let var2 := mulmod( + state0, + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + let var4 := mulmod( + var2, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + mstore( + 0x00, + mulmod( + mulmod( + var4, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + sum() + mstore( + 0x00, + addmod( + mulmod( + 2600766909924179814780409961696866414079699656430070499803459729017893381997, + mload(0x00), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x20, + addmod( + mulmod( + 19293363242678774625215171492393209093707286181479006293654394057747218353607, + mload(0x20), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x80, + addmod( + mulmod( + 21414786808156610356356451480905960406647514095406216853368573063004475600640, + mload(0x80), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xa0, + addmod( + mulmod( + 8215135898581116354906741804378477022438799156627805573019887031189487620936, + mload(0xa0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xc0, + addmod( + mulmod( + 9165814748476180913577766403125055556952884368727238651703828504915350029819, + mload(0xc0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xe0, + addmod( + mulmod( + 15078459252378813527385228808553999657222567675360137586804698725603240352055, + mload(0xe0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x100, + addmod( + mulmod( + 5648186893216350474836221186116590993767413676065426352255299742021094533501, + mload(0x100), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x120, + addmod( + mulmod( + 20725344080263893594397636575905698660034655258256134536883719628954264697683, + mload(0x120), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + { + let state0 := add( + mload(0x00), + 2434370996884752904104098216922445401569159963469965008995898759656475875110 + ) + { + let var2 := mulmod( + state0, + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + let var4 := mulmod( + var2, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + mstore( + 0x00, + mulmod( + mulmod( + var4, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + sum() + mstore( + 0x00, + addmod( + mulmod( + 2600766909924179814780409961696866414079699656430070499803459729017893381997, + mload(0x00), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x20, + addmod( + mulmod( + 19293363242678774625215171492393209093707286181479006293654394057747218353607, + mload(0x20), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x80, + addmod( + mulmod( + 21414786808156610356356451480905960406647514095406216853368573063004475600640, + mload(0x80), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xa0, + addmod( + mulmod( + 8215135898581116354906741804378477022438799156627805573019887031189487620936, + mload(0xa0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xc0, + addmod( + mulmod( + 9165814748476180913577766403125055556952884368727238651703828504915350029819, + mload(0xc0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xe0, + addmod( + mulmod( + 15078459252378813527385228808553999657222567675360137586804698725603240352055, + mload(0xe0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x100, + addmod( + mulmod( + 5648186893216350474836221186116590993767413676065426352255299742021094533501, + mload(0x100), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x120, + addmod( + mulmod( + 20725344080263893594397636575905698660034655258256134536883719628954264697683, + mload(0x120), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + { + let state0 := add( + mload(0x00), + 4137483869981861013775448278496529445656281590765517233881272272161047390551 + ) + { + let var2 := mulmod( + state0, + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + let var4 := mulmod( + var2, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + mstore( + 0x00, + mulmod( + mulmod( + var4, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + sum() + mstore( + 0x00, + addmod( + mulmod( + 2600766909924179814780409961696866414079699656430070499803459729017893381997, + mload(0x00), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x20, + addmod( + mulmod( + 19293363242678774625215171492393209093707286181479006293654394057747218353607, + mload(0x20), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x80, + addmod( + mulmod( + 21414786808156610356356451480905960406647514095406216853368573063004475600640, + mload(0x80), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xa0, + addmod( + mulmod( + 8215135898581116354906741804378477022438799156627805573019887031189487620936, + mload(0xa0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xc0, + addmod( + mulmod( + 9165814748476180913577766403125055556952884368727238651703828504915350029819, + mload(0xc0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xe0, + addmod( + mulmod( + 15078459252378813527385228808553999657222567675360137586804698725603240352055, + mload(0xe0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x100, + addmod( + mulmod( + 5648186893216350474836221186116590993767413676065426352255299742021094533501, + mload(0x100), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x120, + addmod( + mulmod( + 20725344080263893594397636575905698660034655258256134536883719628954264697683, + mload(0x120), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + { + let state0 := add( + mload(0x00), + 5435597430877857909644660105310763099627063893382747901672520731247676814123 + ) + { + let var2 := mulmod( + state0, + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + let var4 := mulmod( + var2, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + mstore( + 0x00, + mulmod( + mulmod( + var4, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + sum() + mstore( + 0x00, + addmod( + mulmod( + 2600766909924179814780409961696866414079699656430070499803459729017893381997, + mload(0x00), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x20, + addmod( + mulmod( + 19293363242678774625215171492393209093707286181479006293654394057747218353607, + mload(0x20), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x80, + addmod( + mulmod( + 21414786808156610356356451480905960406647514095406216853368573063004475600640, + mload(0x80), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xa0, + addmod( + mulmod( + 8215135898581116354906741804378477022438799156627805573019887031189487620936, + mload(0xa0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xc0, + addmod( + mulmod( + 9165814748476180913577766403125055556952884368727238651703828504915350029819, + mload(0xc0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xe0, + addmod( + mulmod( + 15078459252378813527385228808553999657222567675360137586804698725603240352055, + mload(0xe0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x100, + addmod( + mulmod( + 5648186893216350474836221186116590993767413676065426352255299742021094533501, + mload(0x100), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x120, + addmod( + mulmod( + 20725344080263893594397636575905698660034655258256134536883719628954264697683, + mload(0x120), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + { + let state0 := add( + mload(0x00), + 524518289161264304724373110130550500066215933535943135707891179726282748707 + ) + { + let var2 := mulmod( + state0, + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + let var4 := mulmod( + var2, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + mstore( + 0x00, + mulmod( + mulmod( + var4, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + sum() + mstore( + 0x00, + addmod( + mulmod( + 2600766909924179814780409961696866414079699656430070499803459729017893381997, + mload(0x00), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x20, + addmod( + mulmod( + 19293363242678774625215171492393209093707286181479006293654394057747218353607, + mload(0x20), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x80, + addmod( + mulmod( + 21414786808156610356356451480905960406647514095406216853368573063004475600640, + mload(0x80), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xa0, + addmod( + mulmod( + 8215135898581116354906741804378477022438799156627805573019887031189487620936, + mload(0xa0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xc0, + addmod( + mulmod( + 9165814748476180913577766403125055556952884368727238651703828504915350029819, + mload(0xc0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xe0, + addmod( + mulmod( + 15078459252378813527385228808553999657222567675360137586804698725603240352055, + mload(0xe0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x100, + addmod( + mulmod( + 5648186893216350474836221186116590993767413676065426352255299742021094533501, + mload(0x100), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x120, + addmod( + mulmod( + 20725344080263893594397636575905698660034655258256134536883719628954264697683, + mload(0x120), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + { + let state0 := add( + mload(0x00), + 1751307723466358110098512070987508093607034543894162777595610481901356964264 + ) + { + let var2 := mulmod( + state0, + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + let var4 := mulmod( + var2, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + mstore( + 0x00, + mulmod( + mulmod( + var4, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + sum() + mstore( + 0x00, + addmod( + mulmod( + 2600766909924179814780409961696866414079699656430070499803459729017893381997, + mload(0x00), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x20, + addmod( + mulmod( + 19293363242678774625215171492393209093707286181479006293654394057747218353607, + mload(0x20), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x80, + addmod( + mulmod( + 21414786808156610356356451480905960406647514095406216853368573063004475600640, + mload(0x80), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xa0, + addmod( + mulmod( + 8215135898581116354906741804378477022438799156627805573019887031189487620936, + mload(0xa0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xc0, + addmod( + mulmod( + 9165814748476180913577766403125055556952884368727238651703828504915350029819, + mload(0xc0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xe0, + addmod( + mulmod( + 15078459252378813527385228808553999657222567675360137586804698725603240352055, + mload(0xe0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x100, + addmod( + mulmod( + 5648186893216350474836221186116590993767413676065426352255299742021094533501, + mload(0x100), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x120, + addmod( + mulmod( + 20725344080263893594397636575905698660034655258256134536883719628954264697683, + mload(0x120), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + { + let state0 := add( + mload(0x00), + 14379457882544169338616440442319667355116934801723810641671825534922887126311 + ) + { + let var2 := mulmod( + state0, + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + let var4 := mulmod( + var2, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + mstore( + 0x00, + mulmod( + mulmod( + var4, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + sum() + mstore( + 0x00, + addmod( + mulmod( + 2600766909924179814780409961696866414079699656430070499803459729017893381997, + mload(0x00), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x20, + addmod( + mulmod( + 19293363242678774625215171492393209093707286181479006293654394057747218353607, + mload(0x20), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x80, + addmod( + mulmod( + 21414786808156610356356451480905960406647514095406216853368573063004475600640, + mload(0x80), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xa0, + addmod( + mulmod( + 8215135898581116354906741804378477022438799156627805573019887031189487620936, + mload(0xa0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xc0, + addmod( + mulmod( + 9165814748476180913577766403125055556952884368727238651703828504915350029819, + mload(0xc0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xe0, + addmod( + mulmod( + 15078459252378813527385228808553999657222567675360137586804698725603240352055, + mload(0xe0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x100, + addmod( + mulmod( + 5648186893216350474836221186116590993767413676065426352255299742021094533501, + mload(0x100), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x120, + addmod( + mulmod( + 20725344080263893594397636575905698660034655258256134536883719628954264697683, + mload(0x120), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + { + let state0 := add( + mload(0x00), + 17523955073338443114823309995884983834639327123805850756462598717896064390697 + ) + { + let var2 := mulmod( + state0, + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + let var4 := mulmod( + var2, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + mstore( + 0x00, + mulmod( + mulmod( + var4, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + sum() + mstore( + 0x00, + addmod( + mulmod( + 2600766909924179814780409961696866414079699656430070499803459729017893381997, + mload(0x00), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x20, + addmod( + mulmod( + 19293363242678774625215171492393209093707286181479006293654394057747218353607, + mload(0x20), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x80, + addmod( + mulmod( + 21414786808156610356356451480905960406647514095406216853368573063004475600640, + mload(0x80), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xa0, + addmod( + mulmod( + 8215135898581116354906741804378477022438799156627805573019887031189487620936, + mload(0xa0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xc0, + addmod( + mulmod( + 9165814748476180913577766403125055556952884368727238651703828504915350029819, + mload(0xc0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xe0, + addmod( + mulmod( + 15078459252378813527385228808553999657222567675360137586804698725603240352055, + mload(0xe0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x100, + addmod( + mulmod( + 5648186893216350474836221186116590993767413676065426352255299742021094533501, + mload(0x100), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x120, + addmod( + mulmod( + 20725344080263893594397636575905698660034655258256134536883719628954264697683, + mload(0x120), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + { + let state0 := add( + mload(0x00), + 20763445568370636302460408007645878400428156279959803011940918483997397145304 + ) + { + let var2 := mulmod( + state0, + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + let var4 := mulmod( + var2, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + mstore( + 0x00, + mulmod( + mulmod( + var4, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + sum() + mstore( + 0x00, + addmod( + mulmod( + 2600766909924179814780409961696866414079699656430070499803459729017893381997, + mload(0x00), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x20, + addmod( + mulmod( + 19293363242678774625215171492393209093707286181479006293654394057747218353607, + mload(0x20), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x80, + addmod( + mulmod( + 21414786808156610356356451480905960406647514095406216853368573063004475600640, + mload(0x80), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xa0, + addmod( + mulmod( + 8215135898581116354906741804378477022438799156627805573019887031189487620936, + mload(0xa0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xc0, + addmod( + mulmod( + 9165814748476180913577766403125055556952884368727238651703828504915350029819, + mload(0xc0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xe0, + addmod( + mulmod( + 15078459252378813527385228808553999657222567675360137586804698725603240352055, + mload(0xe0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x100, + addmod( + mulmod( + 5648186893216350474836221186116590993767413676065426352255299742021094533501, + mload(0x100), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x120, + addmod( + mulmod( + 20725344080263893594397636575905698660034655258256134536883719628954264697683, + mload(0x120), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + { + let state0 := add( + mload(0x00), + 13892617801935783037491120867832099138633690632189685079093341530264003967791 + ) + { + let var2 := mulmod( + state0, + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + let var4 := mulmod( + var2, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + mstore( + 0x00, + mulmod( + mulmod( + var4, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + sum() + mstore( + 0x00, + addmod( + mulmod( + 2600766909924179814780409961696866414079699656430070499803459729017893381997, + mload(0x00), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x20, + addmod( + mulmod( + 19293363242678774625215171492393209093707286181479006293654394057747218353607, + mload(0x20), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x80, + addmod( + mulmod( + 21414786808156610356356451480905960406647514095406216853368573063004475600640, + mload(0x80), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xa0, + addmod( + mulmod( + 8215135898581116354906741804378477022438799156627805573019887031189487620936, + mload(0xa0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xc0, + addmod( + mulmod( + 9165814748476180913577766403125055556952884368727238651703828504915350029819, + mload(0xc0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xe0, + addmod( + mulmod( + 15078459252378813527385228808553999657222567675360137586804698725603240352055, + mload(0xe0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x100, + addmod( + mulmod( + 5648186893216350474836221186116590993767413676065426352255299742021094533501, + mload(0x100), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x120, + addmod( + mulmod( + 20725344080263893594397636575905698660034655258256134536883719628954264697683, + mload(0x120), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + { + let state0 := add( + mload(0x00), + 1308414123599469965295155060753088653871456878869193033439510811601963545749 + ) + { + let var2 := mulmod( + state0, + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + let var4 := mulmod( + var2, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + mstore( + 0x00, + mulmod( + mulmod( + var4, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + sum() + mstore( + 0x00, + addmod( + mulmod( + 2600766909924179814780409961696866414079699656430070499803459729017893381997, + mload(0x00), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x20, + addmod( + mulmod( + 19293363242678774625215171492393209093707286181479006293654394057747218353607, + mload(0x20), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x80, + addmod( + mulmod( + 21414786808156610356356451480905960406647514095406216853368573063004475600640, + mload(0x80), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xa0, + addmod( + mulmod( + 8215135898581116354906741804378477022438799156627805573019887031189487620936, + mload(0xa0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xc0, + addmod( + mulmod( + 9165814748476180913577766403125055556952884368727238651703828504915350029819, + mload(0xc0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xe0, + addmod( + mulmod( + 15078459252378813527385228808553999657222567675360137586804698725603240352055, + mload(0xe0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x100, + addmod( + mulmod( + 5648186893216350474836221186116590993767413676065426352255299742021094533501, + mload(0x100), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x120, + addmod( + mulmod( + 20725344080263893594397636575905698660034655258256134536883719628954264697683, + mload(0x120), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + { + let state0 := add( + mload(0x00), + 1662344861162290450810513261934733006057888097213770953767445658429321134478 + ) + { + let var2 := mulmod( + state0, + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + let var4 := mulmod( + var2, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + mstore( + 0x00, + mulmod( + mulmod( + var4, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + sum() + mstore( + 0x00, + addmod( + mulmod( + 2600766909924179814780409961696866414079699656430070499803459729017893381997, + mload(0x00), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x20, + addmod( + mulmod( + 19293363242678774625215171492393209093707286181479006293654394057747218353607, + mload(0x20), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x80, + addmod( + mulmod( + 21414786808156610356356451480905960406647514095406216853368573063004475600640, + mload(0x80), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xa0, + addmod( + mulmod( + 8215135898581116354906741804378477022438799156627805573019887031189487620936, + mload(0xa0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xc0, + addmod( + mulmod( + 9165814748476180913577766403125055556952884368727238651703828504915350029819, + mload(0xc0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xe0, + addmod( + mulmod( + 15078459252378813527385228808553999657222567675360137586804698725603240352055, + mload(0xe0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x100, + addmod( + mulmod( + 5648186893216350474836221186116590993767413676065426352255299742021094533501, + mload(0x100), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x120, + addmod( + mulmod( + 20725344080263893594397636575905698660034655258256134536883719628954264697683, + mload(0x120), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + { + let state0 := add( + mload(0x00), + 20443177566820274604835505442424845806635697148027328945828753803047179429262 + ) + { + let var2 := mulmod( + state0, + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + let var4 := mulmod( + var2, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + mstore( + 0x00, + mulmod( + mulmod( + var4, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + sum() + mstore( + 0x00, + addmod( + mulmod( + 2600766909924179814780409961696866414079699656430070499803459729017893381997, + mload(0x00), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x20, + addmod( + mulmod( + 19293363242678774625215171492393209093707286181479006293654394057747218353607, + mload(0x20), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x80, + addmod( + mulmod( + 21414786808156610356356451480905960406647514095406216853368573063004475600640, + mload(0x80), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xa0, + addmod( + mulmod( + 8215135898581116354906741804378477022438799156627805573019887031189487620936, + mload(0xa0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xc0, + addmod( + mulmod( + 9165814748476180913577766403125055556952884368727238651703828504915350029819, + mload(0xc0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xe0, + addmod( + mulmod( + 15078459252378813527385228808553999657222567675360137586804698725603240352055, + mload(0xe0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x100, + addmod( + mulmod( + 5648186893216350474836221186116590993767413676065426352255299742021094533501, + mload(0x100), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x120, + addmod( + mulmod( + 20725344080263893594397636575905698660034655258256134536883719628954264697683, + mload(0x120), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + { + let state0 := add( + mload(0x00), + 8427529718777821395091100109834811066359753665738975680235391126556845526890 + ) + { + let var2 := mulmod( + state0, + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + let var4 := mulmod( + var2, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + mstore( + 0x00, + mulmod( + mulmod( + var4, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + sum() + mstore( + 0x00, + addmod( + mulmod( + 2600766909924179814780409961696866414079699656430070499803459729017893381997, + mload(0x00), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x20, + addmod( + mulmod( + 19293363242678774625215171492393209093707286181479006293654394057747218353607, + mload(0x20), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x80, + addmod( + mulmod( + 21414786808156610356356451480905960406647514095406216853368573063004475600640, + mload(0x80), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xa0, + addmod( + mulmod( + 8215135898581116354906741804378477022438799156627805573019887031189487620936, + mload(0xa0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xc0, + addmod( + mulmod( + 9165814748476180913577766403125055556952884368727238651703828504915350029819, + mload(0xc0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xe0, + addmod( + mulmod( + 15078459252378813527385228808553999657222567675360137586804698725603240352055, + mload(0xe0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x100, + addmod( + mulmod( + 5648186893216350474836221186116590993767413676065426352255299742021094533501, + mload(0x100), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x120, + addmod( + mulmod( + 20725344080263893594397636575905698660034655258256134536883719628954264697683, + mload(0x120), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + { + let state0 := add( + mload(0x00), + 10946983102263150274549536602153963823993597140192081784834807923027311583069 + ) + { + let var2 := mulmod( + state0, + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + let var4 := mulmod( + var2, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + mstore( + 0x00, + mulmod( + mulmod( + var4, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + sum() + mstore( + 0x00, + addmod( + mulmod( + 2600766909924179814780409961696866414079699656430070499803459729017893381997, + mload(0x00), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x20, + addmod( + mulmod( + 19293363242678774625215171492393209093707286181479006293654394057747218353607, + mload(0x20), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x80, + addmod( + mulmod( + 21414786808156610356356451480905960406647514095406216853368573063004475600640, + mload(0x80), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xa0, + addmod( + mulmod( + 8215135898581116354906741804378477022438799156627805573019887031189487620936, + mload(0xa0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xc0, + addmod( + mulmod( + 9165814748476180913577766403125055556952884368727238651703828504915350029819, + mload(0xc0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xe0, + addmod( + mulmod( + 15078459252378813527385228808553999657222567675360137586804698725603240352055, + mload(0xe0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x100, + addmod( + mulmod( + 5648186893216350474836221186116590993767413676065426352255299742021094533501, + mload(0x100), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x120, + addmod( + mulmod( + 20725344080263893594397636575905698660034655258256134536883719628954264697683, + mload(0x120), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + { + let state0 := add( + mload(0x00), + 11157903074510728276165582821675613398204544967484723112588784070444164004252 + ) + { + let var2 := mulmod( + state0, + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + let var4 := mulmod( + var2, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + mstore( + 0x00, + mulmod( + mulmod( + var4, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + sum() + mstore( + 0x00, + addmod( + mulmod( + 2600766909924179814780409961696866414079699656430070499803459729017893381997, + mload(0x00), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x20, + addmod( + mulmod( + 19293363242678774625215171492393209093707286181479006293654394057747218353607, + mload(0x20), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x80, + addmod( + mulmod( + 21414786808156610356356451480905960406647514095406216853368573063004475600640, + mload(0x80), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xa0, + addmod( + mulmod( + 8215135898581116354906741804378477022438799156627805573019887031189487620936, + mload(0xa0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xc0, + addmod( + mulmod( + 9165814748476180913577766403125055556952884368727238651703828504915350029819, + mload(0xc0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xe0, + addmod( + mulmod( + 15078459252378813527385228808553999657222567675360137586804698725603240352055, + mload(0xe0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x100, + addmod( + mulmod( + 5648186893216350474836221186116590993767413676065426352255299742021094533501, + mload(0x100), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x120, + addmod( + mulmod( + 20725344080263893594397636575905698660034655258256134536883719628954264697683, + mload(0x120), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + { + let state0 := add( + mload(0x00), + 14860244753384889920468588445646388769146670323947418785445337100112682476522 + ) + { + let var2 := mulmod( + state0, + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + let var4 := mulmod( + var2, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + mstore( + 0x00, + mulmod( + mulmod( + var4, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + sum() + mstore( + 0x00, + addmod( + mulmod( + 2600766909924179814780409961696866414079699656430070499803459729017893381997, + mload(0x00), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x20, + addmod( + mulmod( + 19293363242678774625215171492393209093707286181479006293654394057747218353607, + mload(0x20), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x80, + addmod( + mulmod( + 21414786808156610356356451480905960406647514095406216853368573063004475600640, + mload(0x80), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xa0, + addmod( + mulmod( + 8215135898581116354906741804378477022438799156627805573019887031189487620936, + mload(0xa0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xc0, + addmod( + mulmod( + 9165814748476180913577766403125055556952884368727238651703828504915350029819, + mload(0xc0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xe0, + addmod( + mulmod( + 15078459252378813527385228808553999657222567675360137586804698725603240352055, + mload(0xe0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x100, + addmod( + mulmod( + 5648186893216350474836221186116590993767413676065426352255299742021094533501, + mload(0x100), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x120, + addmod( + mulmod( + 20725344080263893594397636575905698660034655258256134536883719628954264697683, + mload(0x120), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + { + let state0 := add( + mload(0x00), + 19667868664387897300981027052569110463992131826750586078083601936180553195445 + ) + { + let var2 := mulmod( + state0, + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + let var4 := mulmod( + var2, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + mstore( + 0x00, + mulmod( + mulmod( + var4, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + sum() + mstore( + 0x00, + addmod( + mulmod( + 2600766909924179814780409961696866414079699656430070499803459729017893381997, + mload(0x00), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x20, + addmod( + mulmod( + 19293363242678774625215171492393209093707286181479006293654394057747218353607, + mload(0x20), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x80, + addmod( + mulmod( + 21414786808156610356356451480905960406647514095406216853368573063004475600640, + mload(0x80), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xa0, + addmod( + mulmod( + 8215135898581116354906741804378477022438799156627805573019887031189487620936, + mload(0xa0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xc0, + addmod( + mulmod( + 9165814748476180913577766403125055556952884368727238651703828504915350029819, + mload(0xc0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xe0, + addmod( + mulmod( + 15078459252378813527385228808553999657222567675360137586804698725603240352055, + mload(0xe0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x100, + addmod( + mulmod( + 5648186893216350474836221186116590993767413676065426352255299742021094533501, + mload(0x100), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x120, + addmod( + mulmod( + 20725344080263893594397636575905698660034655258256134536883719628954264697683, + mload(0x120), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + { + let state0 := add( + mload(0x00), + 19175638817684058935402017206319086854147207384592219390853570535784533321715 + ) + { + let var2 := mulmod( + state0, + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + let var4 := mulmod( + var2, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + mstore( + 0x00, + mulmod( + mulmod( + var4, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + sum() + mstore( + 0x00, + addmod( + mulmod( + 2600766909924179814780409961696866414079699656430070499803459729017893381997, + mload(0x00), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x20, + addmod( + mulmod( + 19293363242678774625215171492393209093707286181479006293654394057747218353607, + mload(0x20), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x80, + addmod( + mulmod( + 21414786808156610356356451480905960406647514095406216853368573063004475600640, + mload(0x80), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xa0, + addmod( + mulmod( + 8215135898581116354906741804378477022438799156627805573019887031189487620936, + mload(0xa0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xc0, + addmod( + mulmod( + 9165814748476180913577766403125055556952884368727238651703828504915350029819, + mload(0xc0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xe0, + addmod( + mulmod( + 15078459252378813527385228808553999657222567675360137586804698725603240352055, + mload(0xe0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x100, + addmod( + mulmod( + 5648186893216350474836221186116590993767413676065426352255299742021094533501, + mload(0x100), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x120, + addmod( + mulmod( + 20725344080263893594397636575905698660034655258256134536883719628954264697683, + mload(0x120), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + { + let state0 := add( + mload(0x00), + 12494124141064432118122881935513148491604628118093270612690216186298252805026 + ) + { + let var2 := mulmod( + state0, + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + let var4 := mulmod( + var2, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + mstore( + 0x00, + mulmod( + mulmod( + var4, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + sum() + mstore( + 0x00, + addmod( + mulmod( + 2600766909924179814780409961696866414079699656430070499803459729017893381997, + mload(0x00), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x20, + addmod( + mulmod( + 19293363242678774625215171492393209093707286181479006293654394057747218353607, + mload(0x20), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x80, + addmod( + mulmod( + 21414786808156610356356451480905960406647514095406216853368573063004475600640, + mload(0x80), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xa0, + addmod( + mulmod( + 8215135898581116354906741804378477022438799156627805573019887031189487620936, + mload(0xa0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xc0, + addmod( + mulmod( + 9165814748476180913577766403125055556952884368727238651703828504915350029819, + mload(0xc0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xe0, + addmod( + mulmod( + 15078459252378813527385228808553999657222567675360137586804698725603240352055, + mload(0xe0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x100, + addmod( + mulmod( + 5648186893216350474836221186116590993767413676065426352255299742021094533501, + mload(0x100), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x120, + addmod( + mulmod( + 20725344080263893594397636575905698660034655258256134536883719628954264697683, + mload(0x120), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + { + let state0 := add( + mload(0x00), + 8278699417806537071403341410219479038256244092883863337094398027472670690868 + ) + { + let var2 := mulmod( + state0, + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + let var4 := mulmod( + var2, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + mstore( + 0x00, + mulmod( + mulmod( + var4, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + sum() + mstore( + 0x00, + addmod( + mulmod( + 2600766909924179814780409961696866414079699656430070499803459729017893381997, + mload(0x00), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x20, + addmod( + mulmod( + 19293363242678774625215171492393209093707286181479006293654394057747218353607, + mload(0x20), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x80, + addmod( + mulmod( + 21414786808156610356356451480905960406647514095406216853368573063004475600640, + mload(0x80), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xa0, + addmod( + mulmod( + 8215135898581116354906741804378477022438799156627805573019887031189487620936, + mload(0xa0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xc0, + addmod( + mulmod( + 9165814748476180913577766403125055556952884368727238651703828504915350029819, + mload(0xc0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xe0, + addmod( + mulmod( + 15078459252378813527385228808553999657222567675360137586804698725603240352055, + mload(0xe0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x100, + addmod( + mulmod( + 5648186893216350474836221186116590993767413676065426352255299742021094533501, + mload(0x100), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x120, + addmod( + mulmod( + 20725344080263893594397636575905698660034655258256134536883719628954264697683, + mload(0x120), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + { + let state0 := add( + mload(0x00), + 2049673770720342823071350600438028976114490525766655725520666205884117018879 + ) + { + let var2 := mulmod( + state0, + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + let var4 := mulmod( + var2, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + mstore( + 0x00, + mulmod( + mulmod( + var4, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + sum() + mstore( + 0x00, + addmod( + mulmod( + 2600766909924179814780409961696866414079699656430070499803459729017893381997, + mload(0x00), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x20, + addmod( + mulmod( + 19293363242678774625215171492393209093707286181479006293654394057747218353607, + mload(0x20), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x80, + addmod( + mulmod( + 21414786808156610356356451480905960406647514095406216853368573063004475600640, + mload(0x80), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xa0, + addmod( + mulmod( + 8215135898581116354906741804378477022438799156627805573019887031189487620936, + mload(0xa0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xc0, + addmod( + mulmod( + 9165814748476180913577766403125055556952884368727238651703828504915350029819, + mload(0xc0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xe0, + addmod( + mulmod( + 15078459252378813527385228808553999657222567675360137586804698725603240352055, + mload(0xe0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x100, + addmod( + mulmod( + 5648186893216350474836221186116590993767413676065426352255299742021094533501, + mload(0x100), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x120, + addmod( + mulmod( + 20725344080263893594397636575905698660034655258256134536883719628954264697683, + mload(0x120), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + { + let state0 := add( + mload(0x00), + 15664554456052547545787639212885638054675210894003347948969306359411603741221 + ) + { + let var2 := mulmod( + state0, + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + let var4 := mulmod( + var2, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + mstore( + 0x00, + mulmod( + mulmod( + var4, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + sum() + mstore( + 0x00, + addmod( + mulmod( + 2600766909924179814780409961696866414079699656430070499803459729017893381997, + mload(0x00), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x20, + addmod( + mulmod( + 19293363242678774625215171492393209093707286181479006293654394057747218353607, + mload(0x20), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x80, + addmod( + mulmod( + 21414786808156610356356451480905960406647514095406216853368573063004475600640, + mload(0x80), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xa0, + addmod( + mulmod( + 8215135898581116354906741804378477022438799156627805573019887031189487620936, + mload(0xa0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xc0, + addmod( + mulmod( + 9165814748476180913577766403125055556952884368727238651703828504915350029819, + mload(0xc0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xe0, + addmod( + mulmod( + 15078459252378813527385228808553999657222567675360137586804698725603240352055, + mload(0xe0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x100, + addmod( + mulmod( + 5648186893216350474836221186116590993767413676065426352255299742021094533501, + mload(0x100), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x120, + addmod( + mulmod( + 20725344080263893594397636575905698660034655258256134536883719628954264697683, + mload(0x120), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + { + let state0 := add( + mload(0x00), + 1180146134238569222341211963576419371564143833462002527404875987379102531306 + ) + { + let var2 := mulmod( + state0, + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + let var4 := mulmod( + var2, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + mstore( + 0x00, + mulmod( + mulmod( + var4, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + sum() + mstore( + 0x00, + addmod( + mulmod( + 2600766909924179814780409961696866414079699656430070499803459729017893381997, + mload(0x00), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x20, + addmod( + mulmod( + 19293363242678774625215171492393209093707286181479006293654394057747218353607, + mload(0x20), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x80, + addmod( + mulmod( + 21414786808156610356356451480905960406647514095406216853368573063004475600640, + mload(0x80), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xa0, + addmod( + mulmod( + 8215135898581116354906741804378477022438799156627805573019887031189487620936, + mload(0xa0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xc0, + addmod( + mulmod( + 9165814748476180913577766403125055556952884368727238651703828504915350029819, + mload(0xc0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xe0, + addmod( + mulmod( + 15078459252378813527385228808553999657222567675360137586804698725603240352055, + mload(0xe0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x100, + addmod( + mulmod( + 5648186893216350474836221186116590993767413676065426352255299742021094533501, + mload(0x100), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x120, + addmod( + mulmod( + 20725344080263893594397636575905698660034655258256134536883719628954264697683, + mload(0x120), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + { + let state0 := add( + mload(0x00), + 2962366915552448693827078643390229926763401155127973562286181096651222534835 + ) + { + let var2 := mulmod( + state0, + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + let var4 := mulmod( + var2, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + mstore( + 0x00, + mulmod( + mulmod( + var4, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + sum() + mstore( + 0x00, + addmod( + mulmod( + 2600766909924179814780409961696866414079699656430070499803459729017893381997, + mload(0x00), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x20, + addmod( + mulmod( + 19293363242678774625215171492393209093707286181479006293654394057747218353607, + mload(0x20), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x80, + addmod( + mulmod( + 21414786808156610356356451480905960406647514095406216853368573063004475600640, + mload(0x80), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xa0, + addmod( + mulmod( + 8215135898581116354906741804378477022438799156627805573019887031189487620936, + mload(0xa0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xc0, + addmod( + mulmod( + 9165814748476180913577766403125055556952884368727238651703828504915350029819, + mload(0xc0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xe0, + addmod( + mulmod( + 15078459252378813527385228808553999657222567675360137586804698725603240352055, + mload(0xe0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x100, + addmod( + mulmod( + 5648186893216350474836221186116590993767413676065426352255299742021094533501, + mload(0x100), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x120, + addmod( + mulmod( + 20725344080263893594397636575905698660034655258256134536883719628954264697683, + mload(0x120), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + { + let state0 := add( + mload(0x00), + 8454923055048274473300779886765291623967448890293628249815383532926367395856 + ) + { + let var2 := mulmod( + state0, + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + let var4 := mulmod( + var2, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + mstore( + 0x00, + mulmod( + mulmod( + var4, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + sum() + mstore( + 0x00, + addmod( + mulmod( + 2600766909924179814780409961696866414079699656430070499803459729017893381997, + mload(0x00), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x20, + addmod( + mulmod( + 19293363242678774625215171492393209093707286181479006293654394057747218353607, + mload(0x20), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x80, + addmod( + mulmod( + 21414786808156610356356451480905960406647514095406216853368573063004475600640, + mload(0x80), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xa0, + addmod( + mulmod( + 8215135898581116354906741804378477022438799156627805573019887031189487620936, + mload(0xa0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xc0, + addmod( + mulmod( + 9165814748476180913577766403125055556952884368727238651703828504915350029819, + mload(0xc0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xe0, + addmod( + mulmod( + 15078459252378813527385228808553999657222567675360137586804698725603240352055, + mload(0xe0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x100, + addmod( + mulmod( + 5648186893216350474836221186116590993767413676065426352255299742021094533501, + mload(0x100), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x120, + addmod( + mulmod( + 20725344080263893594397636575905698660034655258256134536883719628954264697683, + mload(0x120), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + { + let state0 := add( + mload(0x00), + 20839238372362818955853198843590566148294159785089189666161332617686692110358 + ) + { + let var2 := mulmod( + state0, + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + let var4 := mulmod( + var2, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + mstore( + 0x00, + mulmod( + mulmod( + var4, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + sum() + mstore( + 0x00, + addmod( + mulmod( + 2600766909924179814780409961696866414079699656430070499803459729017893381997, + mload(0x00), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x20, + addmod( + mulmod( + 19293363242678774625215171492393209093707286181479006293654394057747218353607, + mload(0x20), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x80, + addmod( + mulmod( + 21414786808156610356356451480905960406647514095406216853368573063004475600640, + mload(0x80), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xa0, + addmod( + mulmod( + 8215135898581116354906741804378477022438799156627805573019887031189487620936, + mload(0xa0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xc0, + addmod( + mulmod( + 9165814748476180913577766403125055556952884368727238651703828504915350029819, + mload(0xc0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xe0, + addmod( + mulmod( + 15078459252378813527385228808553999657222567675360137586804698725603240352055, + mload(0xe0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x100, + addmod( + mulmod( + 5648186893216350474836221186116590993767413676065426352255299742021094533501, + mload(0x100), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x120, + addmod( + mulmod( + 20725344080263893594397636575905698660034655258256134536883719628954264697683, + mload(0x120), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + { + let state0 := add( + mload(0x00), + 10429808287581498273991832576203872273646856353727095296202247871323130624874 + ) + { + let var2 := mulmod( + state0, + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + let var4 := mulmod( + var2, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + mstore( + 0x00, + mulmod( + mulmod( + var4, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + sum() + mstore( + 0x00, + addmod( + mulmod( + 2600766909924179814780409961696866414079699656430070499803459729017893381997, + mload(0x00), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x20, + addmod( + mulmod( + 19293363242678774625215171492393209093707286181479006293654394057747218353607, + mload(0x20), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x80, + addmod( + mulmod( + 21414786808156610356356451480905960406647514095406216853368573063004475600640, + mload(0x80), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xa0, + addmod( + mulmod( + 8215135898581116354906741804378477022438799156627805573019887031189487620936, + mload(0xa0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xc0, + addmod( + mulmod( + 9165814748476180913577766403125055556952884368727238651703828504915350029819, + mload(0xc0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xe0, + addmod( + mulmod( + 15078459252378813527385228808553999657222567675360137586804698725603240352055, + mload(0xe0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x100, + addmod( + mulmod( + 5648186893216350474836221186116590993767413676065426352255299742021094533501, + mload(0x100), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x120, + addmod( + mulmod( + 20725344080263893594397636575905698660034655258256134536883719628954264697683, + mload(0x120), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + { + let state0 := add( + mload(0x00), + 9271901703504676095351804139915745802637379886790829560586697548201671614811 + ) + { + let var2 := mulmod( + state0, + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + let var4 := mulmod( + var2, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + mstore( + 0x00, + mulmod( + mulmod( + var4, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + sum() + mstore( + 0x00, + addmod( + mulmod( + 2600766909924179814780409961696866414079699656430070499803459729017893381997, + mload(0x00), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x20, + addmod( + mulmod( + 19293363242678774625215171492393209093707286181479006293654394057747218353607, + mload(0x20), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x80, + addmod( + mulmod( + 21414786808156610356356451480905960406647514095406216853368573063004475600640, + mload(0x80), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xa0, + addmod( + mulmod( + 8215135898581116354906741804378477022438799156627805573019887031189487620936, + mload(0xa0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xc0, + addmod( + mulmod( + 9165814748476180913577766403125055556952884368727238651703828504915350029819, + mload(0xc0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xe0, + addmod( + mulmod( + 15078459252378813527385228808553999657222567675360137586804698725603240352055, + mload(0xe0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x100, + addmod( + mulmod( + 5648186893216350474836221186116590993767413676065426352255299742021094533501, + mload(0x100), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x120, + addmod( + mulmod( + 20725344080263893594397636575905698660034655258256134536883719628954264697683, + mload(0x120), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + { + let state0 := add( + mload(0x00), + 1277029192330597958592137670619290866893426769940867461830690181234653133789 + ) + { + let var2 := mulmod( + state0, + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + let var4 := mulmod( + var2, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + mstore( + 0x00, + mulmod( + mulmod( + var4, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + sum() + mstore( + 0x00, + addmod( + mulmod( + 2600766909924179814780409961696866414079699656430070499803459729017893381997, + mload(0x00), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x20, + addmod( + mulmod( + 19293363242678774625215171492393209093707286181479006293654394057747218353607, + mload(0x20), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x80, + addmod( + mulmod( + 21414786808156610356356451480905960406647514095406216853368573063004475600640, + mload(0x80), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xa0, + addmod( + mulmod( + 8215135898581116354906741804378477022438799156627805573019887031189487620936, + mload(0xa0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xc0, + addmod( + mulmod( + 9165814748476180913577766403125055556952884368727238651703828504915350029819, + mload(0xc0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xe0, + addmod( + mulmod( + 15078459252378813527385228808553999657222567675360137586804698725603240352055, + mload(0xe0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x100, + addmod( + mulmod( + 5648186893216350474836221186116590993767413676065426352255299742021094533501, + mload(0x100), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x120, + addmod( + mulmod( + 20725344080263893594397636575905698660034655258256134536883719628954264697683, + mload(0x120), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + { + let state0 := add( + mload(0x00), + 17446271275185238973758317012506224116792211004689801754888372823248750758368 + ) + { + let var2 := mulmod( + state0, + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + let var4 := mulmod( + var2, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + mstore( + 0x00, + mulmod( + mulmod( + var4, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + sum() + mstore( + 0x00, + addmod( + mulmod( + 2600766909924179814780409961696866414079699656430070499803459729017893381997, + mload(0x00), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x20, + addmod( + mulmod( + 19293363242678774625215171492393209093707286181479006293654394057747218353607, + mload(0x20), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x80, + addmod( + mulmod( + 21414786808156610356356451480905960406647514095406216853368573063004475600640, + mload(0x80), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xa0, + addmod( + mulmod( + 8215135898581116354906741804378477022438799156627805573019887031189487620936, + mload(0xa0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xc0, + addmod( + mulmod( + 9165814748476180913577766403125055556952884368727238651703828504915350029819, + mload(0xc0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xe0, + addmod( + mulmod( + 15078459252378813527385228808553999657222567675360137586804698725603240352055, + mload(0xe0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x100, + addmod( + mulmod( + 5648186893216350474836221186116590993767413676065426352255299742021094533501, + mload(0x100), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x120, + addmod( + mulmod( + 20725344080263893594397636575905698660034655258256134536883719628954264697683, + mload(0x120), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + { + let state0 := add( + mload(0x00), + 18195286995463105065381208020617915527608642263449807357339205385570253103581 + ) + { + let var2 := mulmod( + state0, + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + let var4 := mulmod( + var2, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + mstore( + 0x00, + mulmod( + mulmod( + var4, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + sum() + mstore( + 0x00, + addmod( + mulmod( + 2600766909924179814780409961696866414079699656430070499803459729017893381997, + mload(0x00), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x20, + addmod( + mulmod( + 19293363242678774625215171492393209093707286181479006293654394057747218353607, + mload(0x20), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x80, + addmod( + mulmod( + 21414786808156610356356451480905960406647514095406216853368573063004475600640, + mload(0x80), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xa0, + addmod( + mulmod( + 8215135898581116354906741804378477022438799156627805573019887031189487620936, + mload(0xa0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xc0, + addmod( + mulmod( + 9165814748476180913577766403125055556952884368727238651703828504915350029819, + mload(0xc0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xe0, + addmod( + mulmod( + 15078459252378813527385228808553999657222567675360137586804698725603240352055, + mload(0xe0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x100, + addmod( + mulmod( + 5648186893216350474836221186116590993767413676065426352255299742021094533501, + mload(0x100), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x120, + addmod( + mulmod( + 20725344080263893594397636575905698660034655258256134536883719628954264697683, + mload(0x120), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + { + let state0 := add( + mload(0x00), + 7174788758503182348118464918825059734075283649341444832906374342273234112306 + ) + { + let var2 := mulmod( + state0, + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + let var4 := mulmod( + var2, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + mstore( + 0x00, + mulmod( + mulmod( + var4, + var2, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + state0, + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + sum() + mstore( + 0x00, + addmod( + mulmod( + 2600766909924179814780409961696866414079699656430070499803459729017893381997, + mload(0x00), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x20, + addmod( + mulmod( + 19293363242678774625215171492393209093707286181479006293654394057747218353607, + mload(0x20), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x80, + addmod( + mulmod( + 21414786808156610356356451480905960406647514095406216853368573063004475600640, + mload(0x80), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xa0, + addmod( + mulmod( + 8215135898581116354906741804378477022438799156627805573019887031189487620936, + mload(0xa0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xc0, + addmod( + mulmod( + 9165814748476180913577766403125055556952884368727238651703828504915350029819, + mload(0xc0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0xe0, + addmod( + mulmod( + 15078459252378813527385228808553999657222567675360137586804698725603240352055, + mload(0xe0), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x100, + addmod( + mulmod( + 5648186893216350474836221186116590993767413676065426352255299742021094533501, + mload(0x100), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + mstore( + 0x120, + addmod( + mulmod( + 20725344080263893594397636575905698660034655258256134536883719628954264697683, + mload(0x120), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ), + mload(0x140), + 21888242871839275222246405745257275088548364400416034343698204186575808495617 + ) + ) + } + + { + fr_intro( + 8796514263363206892523807527453045861447267504409085409181921818383118315916, + 16768762997463189144254377645616439451261123095417712027764595809271347822641, + 16981453060376976490300105534864189219102809745136900886818257290108560398681, + 13244378809965474246226965753718500997233021263849978441109990117743824114889, + 12740391142133165804674923445797846244959706391592825821984559861316164389390, + 6357870290401284659894321747392037524252693108822317466922375220086393591413, + 21170287578042370349558117969904573035349234404506160746997342913069492593441, + 16525914224980087240063471205423966448365920546617852056768902032147570692448 + ) + fr_mm() + } + + { + fr_intro( + 15634019475192385983841856902246166130231567044915330197057281032777100628014, + 15211113699235347007597795430087519165406233589182463643807945479646234230239, + 11632581981084267773704718139511950475422868778548965666580599195374884611609, + 5276885296738315848831727579776141799814909987182736480697101231837085016550, + 434949722786700336429895586902875655186339324315727400607943925242711893438, + 12979202789373856152843455289592254071606068472247565795377585881336039887928, + 5516847749540333045414273732117447717673992365056361083316880459671727096711, + 20518987206418619025272040970398156181339077686390712133906274083302454217706 + ) + fr_mm() + } + + { + fr_intro( + 9534878978823325430033643568356022467018975030745926930968329297399586828153, + 16476336232468000195625524343206740870941066529037515612519719879009161459061, + 1926056599060283648268377210224971158820380187985593537994203039766892742929, + 17089075957295284782165638921108879712741772532192826429152480059028756451044, + 3223089692674530160797178366569103602558857774752325464962636799294976059188, + 6416339074787194839206567142761438585611573130765891828761271859398335998072, + 1336837711227185395110000610845274685426861968384488898787321065604521760869, + 3489074920180283241053863308816434113592398030282124098259821386991274215953 + ) + fr_mm() + } + + { + fr_intro( + 8077777888803021630069511342690123744058410620326306901310934661394084426536, + 12303022515875343188934513158193425297350490121987769437868677898104970156809, + 16936067755695119249209357865872131540532280773479227169325938024705653997393, + 14737417545438720305707136711758797913375528370944760259267579780726364876676, + 6161415340932228722932305870854623786821068005781192281048254066342286470096, + 5461556731070720193517122421990625944342168372023166428399391809256130788407, + 19769259359420661267913500180453633636582761819177923247133831646093396706859, + 15388495767943380117723410224640307626534051664851259898259719796404454480030 + ) + fr_mm() + } + return(0x00, 0x20) + } + } +} diff --git a/contracts/Shielder.sol b/contracts/Shielder.sol new file mode 100644 index 00000000..e4d4941c --- /dev/null +++ b/contracts/Shielder.sol @@ -0,0 +1,357 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.26; + +import { IArbSys } from "./IArbSys.sol"; +import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import { MerkleTree } from "./MerkleTree.sol"; +import { OwnableUpgradeable } from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import { PausableUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol"; +import { UIntSet } from "./UIntSet.sol"; +import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; + +interface IVerifier { + function verifyProof( + address vk, + bytes calldata proof, + uint256[] calldata instances + ) external returns (bool); +} + +/// @title Shielder +/// @author CardinalCryptography +contract Shielder is + Initializable, + UUPSUpgradeable, + OwnableUpgradeable, + PausableUpgradeable +{ + using UIntSet for UIntSet.Set; + using MerkleTree for MerkleTree.MerkleTreeData; + + // -- Storage -- + + /// The contract version, in the form `0x{v1}{v2}{v3}`, where: + /// - `v1` is the version of the note schema, + /// - `v1.v2` is the version of the circuits used, + /// - `v1.v2.v3` is the version of the contract itself. + bytes3 public constant CONTRACT_VERSION = 0x000001; + + /// This amount of gas should be sufficient for ether transfers + /// and simple fallback function execution, yet still protecting against reentrancy attack. + uint256 public constant GAS_LIMIT = 3500; + + /// The range check in circuits will work only if we ensure bounded transaction values + /// on the contract side. + uint256 public constant MAX_TRANSACTION_AMOUNT = 2 ** 112 - 1; + + /// Safeguards against a scenario when multiple deposits create a shielded account balance + /// that fails the new account balance range check in the withdrawal circuit, thus + /// making withdrawals impossible. In the contract we can't control a single shielded balance, + /// so we control the sum of balances instead. + uint256 public constant MAX_CONTRACT_BALANCE = MAX_TRANSACTION_AMOUNT; + + /// The temporary limit for the maximal deposit amount in the MVP version. + uint256 public depositLimit; + + /// The address of the Arbitrum system precompile. + address private constant ARB_SYS_ADDRESS = + 0x0000000000000000000000000000000000000064; + IArbSys private arbSysPrecompile; + + // verifier contracts + address public newAccountVerifier; + address public depositVerifier; + address public withdrawVerifier; + + // verification key contracts + address public newAccountVerifyingKey; + address public depositVerifyingKey; + address public withdrawVerifyingKey; + + MerkleTree.MerkleTreeData public merkleTree; + + UIntSet.Set private merkleRoots; + // Mapping from nullifier hash to the block at which it was revealed. Actually, the value will be the block number + 1, + // so that the default value 0 can be used to indicate that the nullifier has not been revealed. + mapping(uint256 => uint256) public nullifiers; + + // -- Events -- + event NewAccountNative( + uint256 idHash, + uint256 amount, + uint256 newNote, + uint256 newNoteIndex + ); + event DepositNative( + uint256 idHiding, + uint256 amount, + uint256 newNote, + uint256 newNoteIndex + ); + event WithdrawNative( + uint256 idHiding, + uint256 amount, + address to, + uint256 newNote, + uint256 newNoteIndex, + address relayerAddress, + uint256 fee + ); + + // -- Errors -- + + error DepositVerificationFailed(); + error DuplicatedNullifier(); + error FeeHigherThanAmount(); + error MerkleRootDoesNotExist(); + error NativeTransferFailed(); + error WithdrawVerificationFailed(); + error NewAccountVerificationFailed(); + error ZeroAmount(); + error AmountOverDepositLimit(); + error AmountTooHigh(); + error ContractBalanceLimitReached(); + error LeafIsNotInTheTree(); + error PrecompileCallFailed(); + + modifier withinDepositLimit() { + if (msg.value > depositLimit) revert AmountOverDepositLimit(); + _; + } + + constructor() { + _disableInitializers(); + } + + /// @dev disable possibility to renounce ownership + function renounceOwnership() public virtual override onlyOwner {} + + function initialize( + address initialOwner, + address _newAccountVerifier, + address _depositVerifier, + address _withdrawVerifier, + address _newAccountVerifyingKey, + address _depositVerifyingKey, + address _withdrawVerifyingKey, + uint256 _depositLimit + ) public initializer { + __Ownable_init(initialOwner); + __Pausable_init(); + _pause(); + + merkleTree.init(); + + arbSysPrecompile = IArbSys(ARB_SYS_ADDRESS); + + newAccountVerifier = _newAccountVerifier; + depositVerifier = _depositVerifier; + withdrawVerifier = _withdrawVerifier; + + newAccountVerifyingKey = _newAccountVerifyingKey; + depositVerifyingKey = _depositVerifyingKey; + withdrawVerifyingKey = _withdrawVerifyingKey; + + depositLimit = _depositLimit; + } + + /// @dev required by the OZ UUPS module + function _authorizeUpgrade(address) internal override onlyOwner {} + + function pause() external onlyOwner { + _pause(); + } + + function unpause() external onlyOwner { + _unpause(); + } + + /* + * Creates a fresh note, with an optional native token deposit. + * + * This transaction serves as the entrypoint to the Shielder. + */ + function newAccountNative( + uint256 newNote, + uint256 idHash, + bytes calldata proof + ) external payable whenNotPaused withinDepositLimit { + uint256 amount = msg.value; + if (nullifiers[idHash] != 0) revert DuplicatedNullifier(); + // `address(this).balance` already includes `msg.value`. + if (address(this).balance > MAX_CONTRACT_BALANCE) + revert ContractBalanceLimitReached(); + + // @dev must follow the same order as in the circuit + uint256[] memory publicInputs = new uint256[](3); + publicInputs[0] = newNote; + publicInputs[1] = idHash; + publicInputs[2] = amount; + + IVerifier _verifier = IVerifier(newAccountVerifier); + bool success = _verifier.verifyProof( + newAccountVerifyingKey, + proof, + publicInputs + ); + + if (!success) revert NewAccountVerificationFailed(); + + uint256 index = merkleTree.addNote(newNote); + merkleRoots.add(merkleTree.root); + registerNullifier(idHash); + + emit NewAccountNative(idHash, amount, newNote, index); + } + + /* + * Make a native token deposit into the Shielder + */ + function depositNative( + uint256 idHiding, + uint256 oldNullifierHash, + uint256 newNote, + uint256 merkleRoot, + bytes calldata proof + ) external payable whenNotPaused withinDepositLimit { + uint256 amount = msg.value; + if (amount == 0) revert ZeroAmount(); + if (nullifiers[oldNullifierHash] != 0) revert DuplicatedNullifier(); + if (!merkleRoots.contains(merkleRoot)) revert MerkleRootDoesNotExist(); + // `address(this).balance` already includes `msg.value`. + if (address(this).balance > MAX_CONTRACT_BALANCE) + revert ContractBalanceLimitReached(); + + // @dev needs to match the order in the circuit + uint256[] memory publicInputs = new uint256[](5); + publicInputs[0] = idHiding; + publicInputs[1] = merkleRoot; + publicInputs[2] = oldNullifierHash; + publicInputs[3] = newNote; + publicInputs[4] = amount; + + IVerifier _verifier = IVerifier(depositVerifier); + bool success = _verifier.verifyProof( + depositVerifyingKey, + proof, + publicInputs + ); + + if (!success) revert DepositVerificationFailed(); + + uint256 index = merkleTree.addNote(newNote); + merkleRoots.add(merkleTree.root); + registerNullifier(oldNullifierHash); + + emit DepositNative(idHiding, msg.value, newNote, index); + } + + /* + * Withdraw shielded native funds + */ + function withdrawNative( + uint256 idHiding, + uint256 amount, + address withdrawAddress, + uint256 merkleRoot, + uint256 oldNullifierHash, + uint256 newNote, + bytes calldata proof, + address relayerAddress, + uint256 relayerFee + ) external whenNotPaused { + if (amount == 0) revert ZeroAmount(); + if (amount <= relayerFee) revert FeeHigherThanAmount(); + if (amount > MAX_TRANSACTION_AMOUNT) revert AmountTooHigh(); + + if (!merkleRoots.contains(merkleRoot)) revert MerkleRootDoesNotExist(); + if (nullifiers[oldNullifierHash] != 0) revert DuplicatedNullifier(); + + // @dev needs to match the order in the circuit + uint256[] memory publicInputs = new uint256[](6); + publicInputs[0] = idHiding; + publicInputs[1] = merkleRoot; + publicInputs[2] = oldNullifierHash; + publicInputs[3] = newNote; + publicInputs[4] = amount; + + bytes memory commitment = abi.encodePacked( + CONTRACT_VERSION, + addressToUInt256(withdrawAddress), + addressToUInt256(relayerAddress), + relayerFee + ); + // @dev shifting right by 4 bits so the commitment is smaller from r + publicInputs[5] = uint256(keccak256(commitment)) >> 4; + + IVerifier _verifier = IVerifier(withdrawVerifier); + bool success = _verifier.verifyProof( + withdrawVerifyingKey, + proof, + publicInputs + ); + + if (!success) revert WithdrawVerificationFailed(); + + uint256 newNoteIndex = merkleTree.addNote(newNote); + merkleRoots.add(merkleTree.root); + registerNullifier(oldNullifierHash); + + // return the tokens + (bool nativeTransferSuccess, ) = withdrawAddress.call{ + value: amount - relayerFee, + gas: GAS_LIMIT + }(""); + if (!nativeTransferSuccess) revert NativeTransferFailed(); + + // pay out the fee + (nativeTransferSuccess, ) = relayerAddress.call{ + value: relayerFee, + gas: GAS_LIMIT + }(""); + if (!nativeTransferSuccess) revert NativeTransferFailed(); + + emit WithdrawNative( + idHiding, + amount, + withdrawAddress, + newNote, + newNoteIndex, + relayerAddress, + relayerFee + ); + } + + function registerNullifier(uint256 nullifier) private { + uint256 blockNumber = arbSysPrecompile.arbBlockNumber(); + nullifiers[nullifier] = blockNumber + 1; + } + + function addressToUInt256(address addr) public pure returns (uint256) { + return uint256(uint160(addr)); + } + + // --- Getters --- + + /* + * Given an index of a leaf return the path from a leaf index to the root, + * omitting the root and leaf for gas efficiency, + * as they can be derived from hashing their children. + */ + + function getMerklePath( + uint256 id + ) external view returns (uint256[] memory) { + return merkleTree.getMerklePath(id); + } + + // -- Setters --- + + /* + * Set the deposit limit for the maximal amount + */ + function setDepositLimit(uint256 _depositLimit) external onlyOwner { + depositLimit = _depositLimit; + } +} diff --git a/contracts/Token.sol b/contracts/Token.sol new file mode 100644 index 00000000..17386621 --- /dev/null +++ b/contracts/Token.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.26; + +import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; + +contract Token is ERC20 { + constructor(uint256 initialSupply) ERC20("MyToken", "MTK") { + _mint(msg.sender, initialSupply); + } +} diff --git a/contracts/UIntSet.sol b/contracts/UIntSet.sol new file mode 100644 index 00000000..87702ef5 --- /dev/null +++ b/contracts/UIntSet.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +library UIntSet { + struct Set { + mapping(uint256 => bool) exists; + } + + function add(Set storage set, uint256 value) internal returns (bool) { + if (!set.exists[value]) { + set.exists[value] = true; + return true; + } + return false; + } + + function contains( + Set storage set, + uint256 value + ) internal view returns (bool) { + return set.exists[value]; + } +} diff --git a/crates/content-encryption/Cargo.toml b/crates/content-encryption/Cargo.toml new file mode 100644 index 00000000..916112a6 --- /dev/null +++ b/crates/content-encryption/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "content-encryption" +version = "0.1.0" +edition.workspace = true +authors.workspace = true +homepage.workspace = true +license.workspace = true +categories.workspace = true +repository.workspace = true +description = "Small library for encrypting and decrypting content with a password." + +[lib] +path = "lib.rs" +name = "content_encryption" + +[dependencies] +anyhow = { workspace = true } +chacha20poly1305 = { workspace = true, features = ["alloc"] } +rust-argon2 = { workspace = true } + +[features] +default = ["std"] +std = [] diff --git a/crates/content-encryption/lib.rs b/crates/content-encryption/lib.rs new file mode 100644 index 00000000..bcaaba2c --- /dev/null +++ b/crates/content-encryption/lib.rs @@ -0,0 +1,42 @@ +//! Small library for encrypting and decrypting content with a password. + +#![deny(missing_docs)] +#![cfg_attr(not(feature = "std"), no_std)] + +extern crate alloc; + +use alloc::vec::Vec; + +use anyhow::{anyhow, Result}; +use chacha20poly1305::{aead::Aead, KeyInit, XChaCha20Poly1305}; + +const SALT: [u8; 32] = [41u8; 32]; +const NONCE: [u8; 24] = [41u8; 24]; + +fn scheme_from_password(password: &[u8]) -> Result { + let key = argon2::hash_raw(password, &SALT, &Default::default()) + .map_err(|e| anyhow!("Failed to derive key from password: {e}"))?; + Ok(XChaCha20Poly1305::new(key.as_slice().into())) +} + +/// Encrypt `content` with `password`. +pub fn encrypt(content: &[u8], password: &[u8]) -> Result> { + scheme_from_password(password)? + .encrypt(NONCE.as_slice().into(), content) + .map_err(|e| anyhow!("Failed to encrypt data: {e}")) +} + +/// Decrypt `content` with `password`. +pub fn decrypt(content: &[u8], password: &[u8]) -> Result> { + scheme_from_password(password)? + .decrypt(NONCE.as_slice().into(), content) + .map_err(|e| anyhow!("Failed to decrypt data - probably the password is incorrect: {e}")) +} + +/// Decrypt `content` with `password` and try converting it to `String` right away. +#[cfg(feature = "std")] +pub fn decrypt_to_string(content: &[u8], password: &[u8]) -> Result { + let decrypted = decrypt(content, password)?; + String::from_utf8(decrypted) + .map_err(|e| anyhow!("Failed to decrypt data - probably the password is incorrect: {e}")) +} diff --git a/crates/evm-utils/Cargo.toml b/crates/evm-utils/Cargo.toml new file mode 100644 index 00000000..ba28fb11 --- /dev/null +++ b/crates/evm-utils/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "evm-utils" +version = "0.1.0" +edition.workspace = true +authors.workspace = true +homepage.workspace = true +license.workspace = true +categories.workspace = true +repository.workspace = true + +[dependencies] +alloy-sol-types = { workspace = true } +hex = { workspace = true } +revm = { workspace = true, default-features = false, features = ["std"] } +revm-interpreter = { workspace = true } +revm-precompile = { workspace = true } +revm-primitives = { workspace = true } +sha3 = { workspace = true } +thiserror = { workspace = true } diff --git a/crates/evm-utils/src/compilation.rs b/crates/evm-utils/src/compilation.rs new file mode 100644 index 00000000..9ade81f6 --- /dev/null +++ b/crates/evm-utils/src/compilation.rs @@ -0,0 +1,93 @@ +use std::{ + io, + io::Write, + process::{Command, Stdio}, +}; + +use crate::repo_root_dir; + +/// Composition of `compile_solidity` and `find_binary` functions. +pub fn source_to_bytecode( + solidity_code: impl AsRef<[u8]>, + contract_name: &str, + decode: bool, +) -> Vec { + let compilation_output = compile_solidity(solidity_code); + find_binary(&compilation_output, contract_name, decode).unwrap() +} + +/// Given solc compilation output returns the bytecode. +/// +/// If `decode` is true, the function will attempt to hex-decode the bytecode. Otherwise, +/// the bytecode is returned as a hex string (as bytes). +pub fn find_binary(input: &str, contract_name: &str, decode: bool) -> Option> { + let search_str = format!("======= :{contract_name} =======\nBinary:\n"); + + // Find the position of the search string in the input + let start = input.find(&search_str)?; + + // Find the end of the hex blob. + let end = input[start + search_str.len()..] + .find('\n') + .map(|pos| pos + start + search_str.len())?; + + // Extract the relevant part of the input that may contain the binary + let binary_section = &input[start + search_str.len()..end].trim(); + + if decode { + hex::decode(binary_section).ok() + } else { + Some(binary_section.as_bytes().to_vec()) + } +} + +/// Compile solidity with `--via-ir` flag, then return creation bytecode. +/// +/// # Panics +/// +/// Panics if executable `solc` can not be found, or compilation fails. +pub fn compile_solidity(solidity: impl AsRef<[u8]>) -> String { + let root_dir = repo_root_dir(); + + let mut process = match Command::new("solc") + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .arg("--bin") + .arg("--via-ir") + .arg("--optimize") + .arg("--base-path") + .arg(&root_dir) + .arg("--include-path") + .arg(root_dir.join("node_modules")) + .arg("--include-path") + .arg(root_dir.join("contracts")) + .arg("-") + .spawn() + { + Ok(process) => process, + Err(err) if err.kind() == io::ErrorKind::NotFound => { + panic!("Command 'solc' not found"); + } + Err(err) => { + panic!("Failed to spawn process with command 'solc':\n{err}"); + } + }; + process + .stdin + .take() + .unwrap() + .write_all(solidity.as_ref()) + .unwrap(); + let output = process.wait_with_output().unwrap(); + + let stderr = output.stderr; + if !stderr.is_empty() { + let error = String::from_utf8(stderr).unwrap(); + if error.contains("Error") { + panic!("Compilation error: {error}"); + } + } + + String::from_utf8(output.stdout).unwrap() +} diff --git a/crates/evm-utils/src/evm_runner.rs b/crates/evm-utils/src/evm_runner.rs new file mode 100644 index 00000000..64271e03 --- /dev/null +++ b/crates/evm-utils/src/evm_runner.rs @@ -0,0 +1,166 @@ +use std::{convert::Infallible, fmt::Debug, fs::File, io::Read}; + +use revm::{ + primitives::{address, Address, EVMError, ExecutionResult, Output, TxKind, U256}, + Evm, InMemoryDB, +}; +use revm_primitives::{AccountInfo, Bytecode, Bytes, Log}; +use thiserror::Error; + +use crate::{compilation::source_to_bytecode, repo_root_dir}; + +/// Evm runner errors +#[derive(Debug, Error)] +#[error(transparent)] +#[non_exhaustive] +#[allow(missing_docs)] +pub enum EvmRunnerError { + #[error("Evm transaction reverted")] + Revert(ExecutionResult), + + #[error("Evm transaction trapped")] + Halt(ExecutionResult), + + #[error("Account does not exist")] + AccountDoesNotExists(Address), + + #[error("Address does not have bytecode")] + AddressDoesNotHaveBytecode(Address), + + #[error("Evm execution error")] + EvmExecution(#[from] EVMError), +} + +pub struct SuccessResult { + pub gas_used: u64, + pub output: Vec, + pub logs: Vec, +} + +/// Evm runner. +#[derive(Debug)] +pub struct EvmRunner { + pub db: InMemoryDB, +} + +fn get_precompile_source() -> String { + let mut source = String::new(); + let mut file = File::open(repo_root_dir().join("contracts/ArbSysMock.sol")) + .expect("Cannot open contract source file"); + file.read_to_string(&mut source) + .expect("Cannot read contract source file"); + source +} + +impl EvmRunner { + pub fn aleph_evm() -> Self { + let mut db = InMemoryDB::default(); + + let precompiles_bytecode = source_to_bytecode(get_precompile_source(), "ArbSysMock", true); + db.insert_account_info( + address!("0000000000000000000000000000000000000064"), + AccountInfo::from_bytecode(Bytecode::new_raw(Bytes::from(precompiles_bytecode))), + ); + + Self { db } + } + + /// Return code size of given address. + pub fn code_size(&self, address: Address) -> Result { + Ok(self + .db + .accounts + .get(&address) + .ok_or(EvmRunnerError::AccountDoesNotExists(address))? + .info + .code + .clone() + .ok_or(EvmRunnerError::AddressDoesNotHaveBytecode(address))? + .len()) + } + + /// Apply `create` transaction with given `bytecode` as creation bytecode. Return created + /// `address`. + pub fn create( + &mut self, + bytecode: Vec, + caller: Option
, + ) -> Result { + let mut evm = Evm::builder() + .with_db(&mut self.db) + .modify_tx_env(|tx| { + tx.caller = caller.unwrap_or(address!("0000000000000000000000000000000000000000")); + tx.gas_limit = u64::MAX; + tx.transact_to = TxKind::Create; + tx.data = bytecode.into(); + tx.chain_id = Some(1); + }) + .modify_cfg_env(|env| { + env.limit_contract_code_size = Some(0x17700); + }) // ~96kb + .build(); + + let result = evm.transact_commit()?; + + match result { + ExecutionResult::Success { output, .. } => match output { + Output::Create(_, Some(address)) => Ok(address), + _ => unreachable!(), + }, + ExecutionResult::Revert { .. } => Err(EvmRunnerError::Revert(result)), + ExecutionResult::Halt { .. } => Err(EvmRunnerError::Halt(result)), + } + } + + /// Apply `call` transaction to given `address` with `calldata`. Return a tuple of `gas_used` + /// and `return_data`. + pub fn call( + &mut self, + address: Address, + calldata: Vec, + caller: Option
, + value: Option, + ) -> Result { + let mut evm = Evm::builder() + .with_db(&mut self.db) + .modify_tx_env(|tx| { + tx.caller = caller.unwrap_or(address!("0000000000000000000000000000000000000000")); + tx.gas_limit = u64::MAX; + tx.transact_to = TxKind::Call(address); + tx.data = calldata.into(); + tx.value = U256::from(value.unwrap_or(U256::ZERO)); + tx.chain_id = Some(1); + }) + .build(); + + let result = evm.transact_commit()?; + + match result { + ExecutionResult::Success { + output, + gas_used, + logs, + .. + } => match output { + Output::Call(value) => Ok(SuccessResult { + gas_used, + output: value.into(), + logs, + }), + _ => unreachable!(), + }, + ExecutionResult::Revert { .. } => Err(EvmRunnerError::Revert(result)), + ExecutionResult::Halt { .. } => Err(EvmRunnerError::Halt(result)), + } + } + + pub fn get_balance(&self, address: Address) -> Result { + Ok(self + .db + .accounts + .get(&address) + .ok_or(EvmRunnerError::AccountDoesNotExists(address))? + .info + .balance) + } +} diff --git a/crates/evm-utils/src/lib.rs b/crates/evm-utils/src/lib.rs new file mode 100644 index 00000000..f90ce47f --- /dev/null +++ b/crates/evm-utils/src/lib.rs @@ -0,0 +1,21 @@ +use std::{env, fs, path::PathBuf}; + +pub use evm_runner::{EvmRunner, EvmRunnerError, SuccessResult}; +pub use revm_primitives; + +pub mod compilation; +mod evm_runner; + +fn repo_root_dir() -> PathBuf { + let mut current_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()); + + while current_dir.pop() { + if let Ok(contents) = fs::read_to_string(current_dir.join("Cargo.toml")) { + if contents.contains("[workspace]") { + return current_dir; + } + } + } + + unreachable!("No workspace directory found") +} diff --git a/crates/halo2-verifier/Acknowledgements b/crates/halo2-verifier/Acknowledgements new file mode 100644 index 00000000..692d26a7 --- /dev/null +++ b/crates/halo2-verifier/Acknowledgements @@ -0,0 +1 @@ +Adopted from https://github.com/privacy-scaling-explorations/halo2-solidity-verifier \ No newline at end of file diff --git a/crates/halo2-verifier/Cargo.toml b/crates/halo2-verifier/Cargo.toml new file mode 100644 index 00000000..9312316a --- /dev/null +++ b/crates/halo2-verifier/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "halo2_solidity_verifier" +version = "0.2.0" +edition = "2021" + +[lib] +name = "halo2_solidity_verifier" +path = "src/lib/lib.rs" + +[[bin]] +name = "halo2_solidity_verifier_generator" +path = "src/generator.rs" + +[dependencies] +alloy-primitives = { workspace = true } +alloy-sol-types = { workspace = true } +askama = { workspace = true, features = ["config"] } +evm-utils = { workspace = true } +halo2_proofs = { workspace = true } +itertools = { workspace = true } +rand = { workspace = true, features = ["small_rng"] } +ruint = { workspace = true } +shielder-circuits = { workspace = true } +shielder-rust-sdk = { workspace = true, features = ["parameter_generation", "powers_of_tau", "conversion"] } diff --git a/crates/halo2-verifier/LICENSE b/crates/halo2-verifier/LICENSE new file mode 100644 index 00000000..245499ec --- /dev/null +++ b/crates/halo2-verifier/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Privacy & Scaling Explorations (formerly known as appliedzkp) + +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/crates/halo2-verifier/Makefile b/crates/halo2-verifier/Makefile new file mode 100644 index 00000000..abf8daa4 --- /dev/null +++ b/crates/halo2-verifier/Makefile @@ -0,0 +1,15 @@ +.PHONY: build +build: ## Build the project + @cargo build --release + +.PHONY: test +test: ## Run tests + @cargo test -- --nocapture + +.PHONY: lint +lint: ## Run clippy and fmt + @cargo clippy --release -- -D warnings + @cargo +nightly fmt --all + +help: ## Displays this help + @awk 'BEGIN {FS = ":.*##"; printf "$(MAKEFILE_NAME)\nUsage:\n make \033[1;36m\033[0m\n\nTargets:\n"} /^[a-zA-Z0-9_-]+:.*?##/ { printf " \033[1;36m%-25s\033[0m %s\n", $$1, $$2 }' $(MAKEFILE_LIST) diff --git a/crates/halo2-verifier/askama.toml b/crates/halo2-verifier/askama.toml new file mode 100644 index 00000000..44f2f2f1 --- /dev/null +++ b/crates/halo2-verifier/askama.toml @@ -0,0 +1,3 @@ +[[escaper]] +path = "askama::Text" +extensions = ["sol"] diff --git a/crates/halo2-verifier/src/generator.rs b/crates/halo2-verifier/src/generator.rs new file mode 100644 index 00000000..43e5b44c --- /dev/null +++ b/crates/halo2-verifier/src/generator.rs @@ -0,0 +1,164 @@ +use std::{fs::File, io::Write, path::PathBuf, str}; + +use halo2_proofs::{ + halo2curves::bn256::{Bn256, Fr}, + poly::kzg::commitment::ParamsKZG, +}; +use halo2_solidity_verifier::{BatchOpenScheme::Bdfg21, SolidityGenerator}; +use shielder_circuits::{ + circuits::{generate_keys_with_min_k, Params}, + consts::RANGE_PROOF_CHUNK_SIZE, + deposit::DepositProverKnowledge, + new_account::NewAccountProverKnowledge, + withdraw::WithdrawProverKnowledge, + EnumCount, ProverKnowledge, MAX_K, +}; +use shielder_rust_sdk::powers_of_tau::{get_ptau_file_path, read as read_setup_parameters, Format}; + +const CONTRACTS_DIR: &str = "./contracts"; + +pub fn main() { + let full_parameters = read_setup_parameters( + get_ptau_file_path(MAX_K, Format::PerpetualPowersOfTau), + Format::PerpetualPowersOfTau, + ) + .expect("failed to read parameters from the ptau file"); + + handle_relation::>(full_parameters.clone(), "NewAccount"); + handle_relation::>( + full_parameters.clone(), + "Deposit", + ); + handle_relation::>( + full_parameters, + "Withdraw", + ); +} + +/// Generate verification key and proving key contracts for the given circuit type. +fn handle_relation>(full_params: Params, relation: &str) { + println!("Generating {relation} relation contracts..."); + let (verifier_solidity, vk_solidity) = generate_solidity_verification_bundle::(full_params); + save_contract_source(&format!("{relation}Verifier.sol"), &verifier_solidity); + save_contract_source(&format!("{relation}VerifyingKey.sol"), &vk_solidity); +} + +/// Given trusted setup, generate Solidity code for the verification key and the verifier. +fn generate_solidity_verification_bundle>( + full_parameters: ParamsKZG, +) -> (String, String) { + let (parameters, _, _, vk) = + generate_keys_with_min_k::(full_parameters).expect("Failed to generate keys"); + SolidityGenerator::new(¶meters, &vk, Bdfg21, PK::PublicInput::COUNT) + .render_separately() + .expect("Failed to generate separate contracts") +} + +/// Writes solidity source code to the file under `CONTRACTS_DIR` directory. +fn save_contract_source(filename: &str, solidity: &str) { + let path = PathBuf::from(format!("{CONTRACTS_DIR}/{filename}")); + File::create(path) + .unwrap() + .write_all(solidity.as_bytes()) + .expect("Can write to file"); +} + +#[cfg(test)] +mod test { + use alloy_primitives::Address; + use alloy_sol_types::SolValue; + use evm_utils::{compilation::source_to_bytecode, EvmRunner, EvmRunnerError, SuccessResult}; + use halo2_proofs::halo2curves::bn256::Fr; + use halo2_solidity_verifier::verifier_contract; + use shielder_circuits::{ + circuits::{generate_proof, generate_setup_params}, + consts::{MAX_K, RANGE_PROOF_CHUNK_SIZE}, + deposit::DepositProverKnowledge, + generate_keys_with_min_k, + new_account::NewAccountProverKnowledge, + withdraw::WithdrawProverKnowledge, + ProverKnowledge, + }; + use shielder_rust_sdk::parameter_generation::rng; + + use crate::generate_solidity_verification_bundle; + + // constants to safeguard against regressions, 110% of MEASURED_GAS + pub const NEW_ACCOUNT_VERIFICATION_GAS_COST: u64 = 706212; //1.1 * 642011; + pub const DEPOSIT_VERIFICATION_GAS_COST: u64 = 914940; //1.1 * 831764; + pub const WITHDRAW_VERIFICATION_GAS_COST: u64 = 1017855; //1.1 * 925323; + + fn deploy_source_code(source: &str, contract_name: &str, evm: &mut EvmRunner) -> Address { + let bytecode = source_to_bytecode(source, contract_name, true); + evm.create(bytecode, None) + .expect("Contract can be deployed") + } + + /// Verify proof and return the gas used + /// + /// Return an error if verifier fails on-chain. + fn verify_with_contract( + verifier_solidity: &str, + vk_solidity: &str, + proof: &[u8], + public_input: &[Fr], + ) -> Result { + let mut evm = EvmRunner::aleph_evm(); + + // Deploy verifier and vk contracts + let verifier_address = deploy_source_code(verifier_solidity, "Halo2Verifier", &mut evm); + let vk_address = deploy_source_code(vk_solidity, "Halo2VerifyingKey", &mut evm); + + // Call verifier contract + let calldata = verifier_contract::encode_calldata(vk_address, proof, public_input); + match evm.call(verifier_address, calldata, None, None) { + Ok(SuccessResult { + gas_used, output, .. + }) => { + println!("Gas cost of verifying: {gas_used}"); + assert!(::abi_decode(&output, true).unwrap()); + Ok(gas_used) + } + Err(why) => Err(why), + } + } + + // Generate proof for an example relation instance and verify it with the Solidity contract. + fn prove_and_verify>(cost_upper_bound: u64) { + let mut rng = rng(); + let full_parameters = generate_setup_params(MAX_K, &mut rng); + let prover_knowledge = PK::random_correct_example(&mut rng); + let public_input = prover_knowledge.serialize_public_input(); + + let (verifier_solidity, vk_solidity) = + generate_solidity_verification_bundle::(full_parameters.clone()); + + let (parameters, _, pk, _) = + generate_keys_with_min_k::(full_parameters).unwrap(); + let circuit = prover_knowledge.create_circuit(); + let proof = generate_proof(¶meters, &pk, circuit, &public_input, &mut rng); + + let result = verify_with_contract(&verifier_solidity, &vk_solidity, &proof, &public_input); + assert!(result.is_ok()); + assert!(result.unwrap() <= cost_upper_bound); + } + + #[test] + fn prove_and_verify_new_account() { + prove_and_verify::>(NEW_ACCOUNT_VERIFICATION_GAS_COST); + } + + #[test] + fn prove_and_verify_deposit() { + prove_and_verify::>( + DEPOSIT_VERIFICATION_GAS_COST, + ); + } + + #[test] + fn prove_and_verify_withdraw() { + prove_and_verify::>( + WITHDRAW_VERIFICATION_GAS_COST, + ); + } +} diff --git a/crates/halo2-verifier/src/lib/codegen.rs b/crates/halo2-verifier/src/lib/codegen.rs new file mode 100644 index 00000000..c23f23f0 --- /dev/null +++ b/crates/halo2-verifier/src/lib/codegen.rs @@ -0,0 +1,302 @@ +use std::fmt::{self, Debug}; + +use halo2_proofs::{ + halo2curves::{bn256, ff::Field}, + plonk::VerifyingKey, + poly::{commitment::ParamsProver, kzg::commitment::ParamsKZG, Rotation}, +}; +use itertools::{chain, Itertools}; +pub use pcs::BatchOpenScheme; +use ruint::aliases::U256; +use shielder_rust_sdk::conversion::field_to_u256; + +use crate::codegen::{ + evaluator::Evaluator, + template::{Halo2Verifier, Halo2VerifyingKey}, + util::{g1_to_u256s, g2_to_u256s, ConstraintSystemMeta, Data, Ptr}, +}; + +mod evaluator; +mod pcs; +mod template; +pub(crate) mod util; + +/// Solidity verifier generator for [`halo2`] proof with KZG polynomial commitment scheme on BN254. +#[derive(Debug)] +pub struct SolidityGenerator<'a> { + params: &'a ParamsKZG, + vk: &'a VerifyingKey, + scheme: BatchOpenScheme, + num_instances: usize, + acc_encoding: Option, + meta: ConstraintSystemMeta, +} + +/// KZG accumulator encoding information. +/// Limbs of each field element are assumed to be least significant limb first. +/// +/// Given instances and `AccumulatorEncoding`, the accumulator will be interpreted as below: +/// ```rust +/// use halo2_proofs::halo2curves::{bn256, ff::{Field, PrimeField}, CurveAffine}; +/// +/// fn accumulator_from_limbs( +/// instances: &[bn256::Fr], +/// offset: usize, +/// num_limbs: usize, +/// num_limb_bits: usize, +/// ) -> (bn256::G1Affine, bn256::G1Affine) { +/// let limbs = |offset| &instances[offset..offset + num_limbs]; +/// let acc_lhs_x = fe_from_limbs(limbs(offset), num_limb_bits); +/// let acc_lhs_y = fe_from_limbs(limbs(offset + num_limbs), num_limb_bits); +/// let acc_rhs_x = fe_from_limbs(limbs(offset + 2 * num_limbs), num_limb_bits); +/// let acc_rhs_y = fe_from_limbs(limbs(offset + 3 * num_limbs), num_limb_bits); +/// let acc_lhs = bn256::G1Affine::from_xy(acc_lhs_x, acc_lhs_y).unwrap(); +/// let acc_rhs = bn256::G1Affine::from_xy(acc_rhs_x, acc_rhs_y).unwrap(); +/// (acc_lhs, acc_rhs) +/// } +/// +/// fn fe_from_limbs(limbs: &[bn256::Fr], num_limb_bits: usize) -> bn256::Fq { +/// limbs.iter().rev().fold(bn256::Fq::ZERO, |acc, limb| { +/// acc * bn256::Fq::from(2).pow_vartime([num_limb_bits as u64]) +/// + bn256::Fq::from_repr_vartime(limb.to_repr()).unwrap() +/// }) +/// } +/// ``` +/// +/// In the end of `verifyProof`, the accumulator will be used to do batched pairing with the +/// pairing input of incoming proof. +#[derive(Clone, Copy, Debug)] +pub struct AccumulatorEncoding { + /// Offset of accumulator limbs in instances. + pub offset: usize, + /// Number of limbs per base field element. + pub num_limbs: usize, + /// Number of bits per limb. + pub num_limb_bits: usize, +} + +impl AccumulatorEncoding { + /// Return a new `AccumulatorEncoding`. + pub fn new(offset: usize, num_limbs: usize, num_limb_bits: usize) -> Self { + Self { + offset, + num_limbs, + num_limb_bits, + } + } +} + +impl<'a> SolidityGenerator<'a> { + /// Return a new `SolidityGenerator`. + pub fn new( + params: &'a ParamsKZG, + vk: &'a VerifyingKey, + scheme: BatchOpenScheme, + num_instances: usize, + ) -> Self { + assert_ne!(vk.cs().num_advice_columns(), 0); + assert!( + vk.cs().num_instance_columns() <= 1, + "Multiple instance columns is not yet implemented" + ); + assert!( + !vk.cs() + .instance_queries() + .iter() + .any(|(_, rotation)| *rotation != Rotation::cur()), + "Rotated query to instance column is not yet implemented" + ); + + Self { + params, + vk, + scheme, + num_instances, + acc_encoding: None, + meta: ConstraintSystemMeta::new(vk.cs()), + } + } + + /// Set `AccumulatorEncoding`. + pub fn set_acc_encoding(mut self, acc_encoding: Option) -> Self { + self.acc_encoding = acc_encoding; + self + } +} + +impl<'a> SolidityGenerator<'a> { + /// Render `Halo2Verifier.sol` with verifying key embedded into writer. + pub fn render_into(&self, verifier_writer: &mut impl fmt::Write) -> Result<(), fmt::Error> { + self.generate_verifier(false).render(verifier_writer) + } + + /// Render `Halo2Verifier.sol` with verifying key embedded and return it as `String`. + pub fn render(&self) -> Result { + let mut verifier_output = String::new(); + self.render_into(&mut verifier_output)?; + Ok(verifier_output) + } + + /// Render `Halo2Verifier.sol` and `Halo2VerifyingKey.sol` into writers. + pub fn render_separately_into( + &self, + verifier_writer: &mut impl fmt::Write, + vk_writer: &mut impl fmt::Write, + ) -> Result<(), fmt::Error> { + self.generate_verifier(true).render(verifier_writer)?; + self.generate_vk().render(vk_writer)?; + Ok(()) + } + + /// Render `Halo2Verifier.sol` and `Halo2VerifyingKey.sol` and return them as `String`. + pub fn render_separately(&self) -> Result<(String, String), fmt::Error> { + let mut verifier_output = String::new(); + let mut vk_output = String::new(); + self.render_separately_into(&mut verifier_output, &mut vk_output)?; + Ok((verifier_output, vk_output)) + } + + fn generate_vk(&self) -> Halo2VerifyingKey { + let constants = { + let domain = self.vk.get_domain(); + let vk_digest = field_to_u256(self.vk.transcript_repr()); + let num_instances = U256::from(self.num_instances); + let k = U256::from(domain.k()); + let n_inv = field_to_u256(bn256::Fr::from(1 << domain.k()).invert().unwrap()); + let omega = field_to_u256(domain.get_omega()); + let omega_inv = field_to_u256(domain.get_omega_inv()); + let omega_inv_to_l = { + let l = self.meta.rotation_last.unsigned_abs() as u64; + field_to_u256(domain.get_omega_inv().pow_vartime([l])) + }; + let has_accumulator = U256::from(self.acc_encoding.is_some() as usize); + let acc_offset = self + .acc_encoding + .map(|acc_encoding| U256::from(acc_encoding.offset)) + .unwrap_or_default(); + let num_acc_limbs = self + .acc_encoding + .map(|acc_encoding| U256::from(acc_encoding.num_limbs)) + .unwrap_or_default(); + let num_acc_limb_bits = self + .acc_encoding + .map(|acc_encoding| U256::from(acc_encoding.num_limb_bits)) + .unwrap_or_default(); + let g1 = self.params.get_g()[0]; + let g1 = g1_to_u256s(g1); + let g2 = g2_to_u256s(self.params.g2()); + let neg_s_g2 = g2_to_u256s(-self.params.s_g2()); + vec![ + ("vk_digest", vk_digest), + ("num_instances", num_instances), + ("k", k), + ("n_inv", n_inv), + ("omega", omega), + ("omega_inv", omega_inv), + ("omega_inv_to_l", omega_inv_to_l), + ("has_accumulator", has_accumulator), + ("acc_offset", acc_offset), + ("num_acc_limbs", num_acc_limbs), + ("num_acc_limb_bits", num_acc_limb_bits), + ("g1_x", g1[0]), + ("g1_y", g1[1]), + ("g2_x_1", g2[0]), + ("g2_x_2", g2[1]), + ("g2_y_1", g2[2]), + ("g2_y_2", g2[3]), + ("neg_s_g2_x_1", neg_s_g2[0]), + ("neg_s_g2_x_2", neg_s_g2[1]), + ("neg_s_g2_y_1", neg_s_g2[2]), + ("neg_s_g2_y_2", neg_s_g2[3]), + ] + }; + let fixed_comms = chain![self.vk.fixed_commitments()] + .flat_map(g1_to_u256s) + .tuples() + .collect(); + let permutation_comms = chain![self.vk.permutation().commitments()] + .flat_map(g1_to_u256s) + .tuples() + .collect(); + Halo2VerifyingKey { + constants, + fixed_comms, + permutation_comms, + } + } + + fn generate_verifier(&self, separate: bool) -> Halo2Verifier { + let proof_cptr = Ptr::calldata(if separate { 0x84 } else { 0x64 }); + + let vk = self.generate_vk(); + let vk_len = vk.len(); + let vk_mptr = Ptr::memory(self.static_working_memory_size(&vk, proof_cptr)); + let data = Data::new(&self.meta, &vk, vk_mptr, proof_cptr); + + let evaluator = Evaluator::new(self.vk.cs(), &self.meta, &data); + let quotient_eval_numer_computations = chain![ + evaluator.gate_computations(), + evaluator.permutation_computations(), + evaluator.lookup_computations() + ] + .enumerate() + .map(|(idx, (mut lines, var))| { + let line = if idx == 0 { + format!("quotient_eval_numer := {var}") + } else { + format!( + "quotient_eval_numer := addmod(mulmod(quotient_eval_numer, y, r), {var}, r)" + ) + }; + lines.push(line); + lines + }) + .collect(); + + let pcs_computations = self.scheme.computations(&self.meta, &data); + + Halo2Verifier { + scheme: self.scheme, + embedded_vk: (!separate).then_some(vk), + vk_len, + vk_mptr, + num_neg_lagranges: self.meta.rotation_last.unsigned_abs() as usize, + num_advices: self.meta.num_advices(), + num_challenges: self.meta.num_challenges(), + num_rotations: self.meta.num_rotations, + num_evals: self.meta.num_evals, + num_quotients: self.meta.num_quotients, + proof_cptr, + quotient_comm_cptr: data.quotient_comm_cptr, + proof_len: self.meta.proof_len(self.scheme), + challenge_mptr: data.challenge_mptr, + theta_mptr: data.theta_mptr, + quotient_eval_numer_computations, + pcs_computations, + } + } + + fn static_working_memory_size(&self, vk: &Halo2VerifyingKey, proof_cptr: Ptr) -> usize { + let pcs_computation = { + let mock_vk_mptr = Ptr::memory(0x100000); + let mock = Data::new(&self.meta, vk, mock_vk_mptr, proof_cptr); + self.scheme.static_working_memory_size(&self.meta, &mock) + }; + + itertools::max([ + // Keccak256 input (can overwrite vk) + itertools::max(chain![ + self.meta.num_advices().into_iter().map(|n| n * 2 + 1), + [self.meta.num_evals + 1], + ]) + .unwrap() + .saturating_sub(vk.len() / 0x20), + // PCS computation + pcs_computation, + // Pairing + 12, + ]) + .unwrap() + * 0x20 + } +} diff --git a/crates/halo2-verifier/src/lib/codegen/evaluator.rs b/crates/halo2-verifier/src/lib/codegen/evaluator.rs new file mode 100644 index 00000000..814be370 --- /dev/null +++ b/crates/halo2-verifier/src/lib/codegen/evaluator.rs @@ -0,0 +1,373 @@ +#![allow(clippy::useless_format)] + +use std::{cell::RefCell, cmp::Ordering, collections::HashMap, iter}; + +use halo2_proofs::{ + halo2curves::ff::PrimeField, + plonk::{ + Advice, AdviceQuery, Any, Challenge, ConstraintSystem, Expression, Fixed, FixedQuery, Gate, + InstanceQuery, + }, +}; +use itertools::{chain, izip, Itertools}; +use ruint::aliases::U256; +use shielder_rust_sdk::conversion::field_to_u256; + +use crate::codegen::util::{code_block, ConstraintSystemMeta, Data}; + +#[derive(Debug)] +pub(crate) struct Evaluator<'a, F: PrimeField> { + cs: &'a ConstraintSystem, + meta: &'a ConstraintSystemMeta, + data: &'a Data, + var_counter: RefCell, + var_cache: RefCell>, +} + +impl<'a, F> Evaluator<'a, F> +where + F: PrimeField, +{ + pub(crate) fn new( + cs: &'a ConstraintSystem, + meta: &'a ConstraintSystemMeta, + data: &'a Data, + ) -> Self { + Self { + cs, + meta, + data, + var_counter: Default::default(), + var_cache: Default::default(), + } + } + + pub fn gate_computations(&self) -> Vec<(Vec, String)> { + self.cs + .gates() + .iter() + .flat_map(Gate::polynomials) + .map(|expression| self.evaluate_and_reset(expression)) + .collect() + } + + pub fn permutation_computations(&self) -> Vec<(Vec, String)> { + let Self { meta, data, .. } = self; + let last_chunk_idx = meta.num_permutation_zs - 1; + chain![ + data.permutation_z_evals.first().map(|(z, _, _)| { + vec![ + format!("let l_0 := mload(L_0_MPTR)"), + format!("let eval := addmod(l_0, sub(r, mulmod(l_0, {z}, r)), r)"), + ] + }), + data.permutation_z_evals.last().map(|(z, _, _)| { + let item = "addmod(mulmod(perm_z_last, perm_z_last, r), sub(r, perm_z_last), r)"; + vec![ + format!("let perm_z_last := {z}"), + format!("let eval := mulmod(mload(L_LAST_MPTR), {item}, r)"), + ] + }), + data.permutation_z_evals.iter().tuple_windows().map( + |((_, _, z_i_last), (z_j, _, _))| { + let item = format!("addmod({z_j}, sub(r, {z_i_last}), r)"); + vec![format!("let eval := mulmod(mload(L_0_MPTR), {item}, r)")] + } + ), + izip!( + meta.permutation_columns.chunks(meta.permutation_chunk_len), + &data.permutation_z_evals, + ) + .enumerate() + .map(|(chunk_idx, (columns, evals))| { + let last_column_idx = columns.len() - 1; + chain![ + [ + format!("let gamma := mload(GAMMA_MPTR)"), + format!("let beta := mload(BETA_MPTR)"), + format!("let lhs := {}", evals.1), + format!("let rhs := {}", evals.0), + ], + columns.iter().flat_map(|column| { + let perm_eval = &data.permutation_evals[column]; + let eval = self.eval(*column.column_type(), column.index(), 0); + let item = format!("mulmod(beta, {perm_eval}, r)"); + [format!( + "lhs := mulmod(lhs, addmod(addmod({eval}, {item}, r), gamma, r), r)" + )] + }), + (chunk_idx == 0) + .then(|| "mstore(0x00, mulmod(beta, mload(X_MPTR), r))".to_string()), + columns.iter().enumerate().flat_map(|(idx, column)| { + let eval = self.eval(*column.column_type(), column.index(), 0); + let item = format!("addmod(addmod({eval}, mload(0x00), r), gamma, r)"); + chain![ + [format!("rhs := mulmod(rhs, {item}, r)")], + (!(chunk_idx == last_chunk_idx && idx == last_column_idx)) + .then(|| "mstore(0x00, mulmod(mload(0x00), delta, r))".to_string()), + ] + }), + { + let item = format!("addmod(mload(L_LAST_MPTR), mload(L_BLIND_MPTR), r)"); + let item = format!("sub(r, mulmod(left_sub_right, {item}, r))"); + [ + format!("let left_sub_right := addmod(lhs, sub(r, rhs), r)"), + format!("let eval := addmod(left_sub_right, {item}, r)"), + ] + } + ] + .collect_vec() + }) + ] + .zip(iter::repeat("eval".to_string())) + .collect() + } + + pub fn lookup_computations(&self) -> Vec<(Vec, String)> { + let input_tables = self + .cs + .lookups() + .iter() + .map(|lookup| { + let [(input_lines, inputs), (table_lines, tables)] = + [lookup.input_expressions(), lookup.table_expressions()].map(|expressions| { + let (lines, inputs) = expressions + .iter() + .map(|expression| self.evaluate(expression)) + .fold((Vec::new(), Vec::new()), |mut acc, result| { + acc.0.extend(result.0); + acc.1.push(result.1); + acc + }); + self.reset(); + (lines, inputs) + }); + (input_lines, inputs, table_lines, tables) + }) + .collect_vec(); + izip!(input_tables, &self.data.lookup_evals) + .flat_map(|(input_table, evals)| { + let (input_lines, inputs, table_lines, tables) = input_table; + let (input_0, rest_inputs) = inputs.split_first().unwrap(); + let (table_0, rest_tables) = tables.split_first().unwrap(); + let (z, z_next, p_input, p_input_prev, p_table) = evals; + [ + vec![ + format!("let l_0 := mload(L_0_MPTR)"), + format!("let eval := addmod(l_0, mulmod(l_0, sub(r, {z}), r), r)"), + ], + { + let item = format!("addmod(mulmod({z}, {z}, r), sub(r, {z}), r)"); + vec![ + format!("let l_last := mload(L_LAST_MPTR)"), + format!("let eval := mulmod(l_last, {item}, r)"), + ] + }, + chain![ + ["let theta := mload(THETA_MPTR)", "let input"].map(str::to_string), + code_block::<1, false>(chain![ + input_lines, + [format!("input := {input_0}")], + rest_inputs.iter().map(|input| format!( + "input := addmod(mulmod(input, theta, r), {input}, r)" + )) + ]), + ["let table"].map(str::to_string), + code_block::<1, false>(chain![ + table_lines, + [format!("table := {table_0}")], + rest_tables.iter().map(|table| format!( + "table := addmod(mulmod(table, theta, r), {table}, r)" + )) + ]), + { + let lhs = format!("addmod({p_input}, beta, r)"); + let rhs = format!("addmod({p_table}, gamma, r)"); + let permuted = format!("mulmod({lhs}, {rhs}, r)"); + let input = + "mulmod(addmod(input, beta, r), addmod(table, gamma, r), r)"; + [ + format!("let beta := mload(BETA_MPTR)"), + format!("let gamma := mload(GAMMA_MPTR)"), + format!("let lhs := mulmod({z_next}, {permuted}, r)"), + format!("let rhs := mulmod({z}, {input}, r)"), + ] + }, + { + let l_inactive = "addmod(mload(L_BLIND_MPTR), mload(L_LAST_MPTR), r)"; + let l_active = format!("addmod(1, sub(r, {l_inactive}), r)"); + [format!( + "let eval := mulmod({l_active}, addmod(lhs, sub(r, rhs), r), r)" + )] + }, + ] + .collect_vec(), + { + let l_0 = "mload(L_0_MPTR)"; + let item = format!("addmod({p_input}, sub(r, {p_table}), r)"); + vec![format!("let eval := mulmod({l_0}, {item}, r)")] + }, + { + let l_inactive = "addmod(mload(L_BLIND_MPTR), mload(L_LAST_MPTR), r)"; + let l_active = format!("addmod(1, sub(r, {l_inactive}), r)"); + let lhs = format!("addmod({p_input}, sub(r, {p_table}), r)"); + let rhs = format!("addmod({p_input}, sub(r, {p_input_prev}), r)"); + vec![format!( + "let eval := mulmod({l_active}, mulmod({lhs}, {rhs}, r), r)" + )] + }, + ] + }) + .zip(iter::repeat("eval".to_string())) + .collect_vec() + } + + fn eval(&self, column_type: impl Into, column_index: usize, rotation: i32) -> String { + match column_type.into() { + Any::Advice(_) => self.data.advice_evals[&(column_index, rotation)].to_string(), + Any::Fixed => self.data.fixed_evals[&(column_index, rotation)].to_string(), + Any::Instance => self.data.instance_eval.to_string(), + } + } + + fn reset(&self) { + *self.var_counter.borrow_mut() = Default::default(); + *self.var_cache.borrow_mut() = Default::default(); + } + + fn evaluate_and_reset(&self, expression: &Expression) -> (Vec, String) { + let result = self.evaluate(expression); + self.reset(); + result + } + + fn evaluate(&self, expression: &Expression) -> (Vec, String) { + evaluate( + expression, + &|constant| { + let constant = u256_string(constant); + self.init_var(constant, None) + }, + &|query| { + self.init_var( + self.eval(Fixed, query.column_index(), query.rotation().0), + Some(fixed_eval_var(query)), + ) + }, + &|query| { + self.init_var( + self.eval(Advice::default(), query.column_index(), query.rotation().0), + Some(advice_eval_var(query)), + ) + }, + &|_| self.init_var(self.data.instance_eval, Some("i_eval".to_string())), + &|challenge| { + self.init_var( + self.data.challenges[challenge.index()], + Some(format!("c_{}", challenge.index())), + ) + }, + &|(mut acc, var)| { + let (lines, var) = self.init_var(format!("sub(r, {var})"), None); + acc.extend(lines); + (acc, var) + }, + &|(mut lhs_acc, lhs_var), (rhs_acc, rhs_var)| { + let (lines, var) = self.init_var(format!("addmod({lhs_var}, {rhs_var}, r)"), None); + lhs_acc.extend(rhs_acc); + lhs_acc.extend(lines); + (lhs_acc, var) + }, + &|(mut lhs_acc, lhs_var), (rhs_acc, rhs_var)| { + let (lines, var) = self.init_var(format!("mulmod({lhs_var}, {rhs_var}, r)"), None); + lhs_acc.extend(rhs_acc); + lhs_acc.extend(lines); + (lhs_acc, var) + }, + &|(mut acc, var), scalar| { + let scalar = u256_string(scalar); + let (lines, var) = self.init_var(format!("mulmod({var}, {scalar}, r)"), None); + acc.extend(lines); + (acc, var) + }, + ) + } + + fn init_var(&self, value: impl ToString, var: Option) -> (Vec, String) { + let value = value.to_string(); + if self.var_cache.borrow().contains_key(&value) { + (vec![], self.var_cache.borrow()[&value].clone()) + } else { + let var = var.unwrap_or_else(|| self.next_var()); + self.var_cache + .borrow_mut() + .insert(value.clone(), var.clone()); + (vec![format!("let {var} := {value}")], var) + } + } + + fn next_var(&self) -> String { + let count = *self.var_counter.borrow(); + *self.var_counter.borrow_mut() += 1; + format!("var{count}") + } +} + +fn u256_string(value: U256) -> String { + if value.bit_len() < 64 { + format!("0x{:x}", value.as_limbs()[0]) + } else { + format!("0x{value:x}") + } +} + +fn fixed_eval_var(fixed_query: FixedQuery) -> String { + column_eval_var("f", fixed_query.column_index(), fixed_query.rotation().0) +} + +fn advice_eval_var(advice_query: AdviceQuery) -> String { + column_eval_var("a", advice_query.column_index(), advice_query.rotation().0) +} + +fn column_eval_var(prefix: &'static str, column_index: usize, rotation: i32) -> String { + match rotation.cmp(&0) { + Ordering::Less => format!("{prefix}_{column_index}_prev_{}", rotation.abs()), + Ordering::Equal => format!("{prefix}_{column_index}"), + Ordering::Greater => format!("{prefix}_{column_index}_next_{rotation}"), + } +} + +#[allow(clippy::too_many_arguments)] +fn evaluate( + expression: &Expression, + constant: &impl Fn(U256) -> T, + fixed: &impl Fn(FixedQuery) -> T, + advice: &impl Fn(AdviceQuery) -> T, + instance: &impl Fn(InstanceQuery) -> T, + challenge: &impl Fn(Challenge) -> T, + negated: &impl Fn(T) -> T, + sum: &impl Fn(T, T) -> T, + product: &impl Fn(T, T) -> T, + scaled: &impl Fn(T, U256) -> T, +) -> T +where + F: PrimeField, +{ + let evaluate = |expr| { + evaluate( + expr, constant, fixed, advice, instance, challenge, negated, sum, product, scaled, + ) + }; + match expression { + Expression::Constant(scalar) => constant(field_to_u256(*scalar)), + Expression::Selector(_) => unreachable!(), + Expression::Fixed(query) => fixed(*query), + Expression::Advice(query) => advice(*query), + Expression::Instance(query) => instance(*query), + Expression::Challenge(value) => challenge(*value), + Expression::Negated(value) => negated(evaluate(value)), + Expression::Sum(lhs, rhs) => sum(evaluate(lhs), evaluate(rhs)), + Expression::Product(lhs, rhs) => product(evaluate(lhs), evaluate(rhs)), + Expression::Scaled(value, scalar) => scaled(evaluate(value), field_to_u256(*scalar)), + } +} diff --git a/crates/halo2-verifier/src/lib/codegen/pcs.rs b/crates/halo2-verifier/src/lib/codegen/pcs.rs new file mode 100644 index 00000000..5e01a43a --- /dev/null +++ b/crates/halo2-verifier/src/lib/codegen/pcs.rs @@ -0,0 +1,104 @@ +use itertools::{chain, izip}; + +use crate::codegen::util::{ConstraintSystemMeta, Data, EcPoint, Word}; + +mod bdfg21; +mod gwc19; + +/// KZG batch open schemes in `halo2`. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum BatchOpenScheme { + /// Batch open scheme in [Plonk] paper. + /// Corresponding to `halo2_proofs::poly::kzg::multiopen::ProverGWC` + /// + /// [Plonk]: https://eprint.iacr.org/2019/953.pdf + Gwc19, + /// Batch open scheme in [BDFG21] paper. + /// Corresponding to `halo2_proofs::poly::kzg::multiopen::ProverSHPLONK` + /// + /// [BDFG21]: https://eprint.iacr.org/2020/081.pdf + Bdfg21, +} + +impl BatchOpenScheme { + pub(crate) fn static_working_memory_size( + &self, + meta: &ConstraintSystemMeta, + data: &Data, + ) -> usize { + match self { + Self::Bdfg21 => bdfg21::static_working_memory_size(meta, data), + Self::Gwc19 => gwc19::static_working_memory_size(meta, data), + } + } + + pub(crate) fn computations( + &self, + meta: &ConstraintSystemMeta, + data: &Data, + ) -> Vec> { + match self { + Self::Bdfg21 => bdfg21::computations(meta, data), + Self::Gwc19 => gwc19::computations(meta, data), + } + } +} + +#[derive(Debug)] +pub(crate) struct Query { + comm: EcPoint, + rot: i32, + eval: Word, +} + +impl Query { + fn new(comm: EcPoint, rot: i32, eval: Word) -> Self { + Self { comm, rot, eval } + } +} + +pub(crate) fn queries(meta: &ConstraintSystemMeta, data: &Data) -> Vec { + chain![ + meta.advice_queries.iter().map(|query| { + let comm = data.advice_comms[query.0]; + let eval = data.advice_evals[query]; + Query::new(comm, query.1, eval) + }), + izip!(&data.permutation_z_comms, &data.permutation_z_evals).flat_map(|(&comm, evals)| { + [Query::new(comm, 0, evals.0), Query::new(comm, 1, evals.1)] + }), + izip!(&data.permutation_z_comms, &data.permutation_z_evals) + .rev() + .skip(1) + .map(|(&comm, evals)| Query::new(comm, meta.rotation_last, evals.2)), + izip!( + &data.lookup_permuted_comms, + &data.lookup_z_comms, + &data.lookup_evals + ) + .flat_map(|(permuted_comms, &z_comm, evals)| { + [ + Query::new(z_comm, 0, evals.0), + Query::new(permuted_comms.0, 0, evals.2), + Query::new(permuted_comms.1, 0, evals.4), + Query::new(permuted_comms.0, -1, evals.3), + Query::new(z_comm, 1, evals.1), + ] + }), + meta.fixed_queries.iter().map(|query| { + let comm = data.fixed_comms[query.0]; + let eval = data.fixed_evals[query]; + Query::new(comm, query.1, eval) + }), + meta.permutation_columns.iter().map(|column| { + let comm = data.permutation_comms[column]; + let eval = data.permutation_evals[column]; + Query::new(comm, 0, eval) + }), + [ + Query::new(data.computed_quotient_comm, 0, data.computed_quotient_eval), + Query::new(data.random_comm, 0, data.random_eval), + ] + ] + .collect() +} diff --git a/crates/halo2-verifier/src/lib/codegen/pcs/bdfg21.rs b/crates/halo2-verifier/src/lib/codegen/pcs/bdfg21.rs new file mode 100644 index 00000000..b0098625 --- /dev/null +++ b/crates/halo2-verifier/src/lib/codegen/pcs/bdfg21.rs @@ -0,0 +1,494 @@ +#![allow(clippy::useless_format)] + +use std::collections::{BTreeMap, BTreeSet}; + +use itertools::{chain, izip, Itertools}; + +use crate::codegen::{ + pcs::{queries, Query}, + util::{ + for_loop, group_backward_adjacent_ec_points, group_backward_adjacent_words, + ConstraintSystemMeta, Data, EcPoint, Location, Ptr, Word, + }, +}; + +pub(super) fn static_working_memory_size(meta: &ConstraintSystemMeta, data: &Data) -> usize { + let (superset, sets) = rotation_sets(&queries(meta, data)); + let num_coeffs = sets.iter().map(|set| set.rots().len()).sum::(); + 2 * (1 + num_coeffs) + 6 + 2 * superset.len() + 1 + 3 * sets.len() +} + +pub(super) fn computations(meta: &ConstraintSystemMeta, data: &Data) -> Vec> { + let (superset, sets) = rotation_sets(&queries(meta, data)); + let min_rot = *superset.first().unwrap(); + let max_rot = *superset.last().unwrap(); + let num_coeffs = sets.iter().map(|set| set.rots().len()).sum::(); + + let w = EcPoint::from(data.w_cptr); + let w_prime = EcPoint::from(data.w_cptr + 2); + + let diff_0 = Word::from(Ptr::memory(0x00)); + let coeffs = sets + .iter() + .scan(diff_0.ptr() + 1, |state, set| { + let ptrs = Word::range(*state).take(set.rots().len()).collect_vec(); + *state = *state + set.rots().len(); + Some(ptrs) + }) + .collect_vec(); + + let first_batch_invert_end = diff_0.ptr() + 1 + num_coeffs; + let second_batch_invert_end = diff_0.ptr() + sets.len(); + let free_mptr = diff_0.ptr() + 2 * (1 + num_coeffs) + 6; + + let point_mptr = free_mptr; + let mu_minus_point_mptr = point_mptr + superset.len(); + let vanishing_0_mptr = mu_minus_point_mptr + superset.len(); + let diff_mptr = vanishing_0_mptr + 1; + let r_eval_mptr = diff_mptr + sets.len(); + let sum_mptr = r_eval_mptr + sets.len(); + + let point_vars = + izip!(&superset, (0..).map(|idx| format!("point_{idx}"))).collect::>(); + let points = izip!(&superset, Word::range(point_mptr)).collect::>(); + let mu_minus_points = + izip!(&superset, Word::range(mu_minus_point_mptr)).collect::>(); + let vanishing_0 = Word::from(vanishing_0_mptr); + let diffs = Word::range(diff_mptr).take(sets.len()).collect_vec(); + let r_evals = Word::range(r_eval_mptr).take(sets.len()).collect_vec(); + let sums = Word::range(sum_mptr).take(sets.len()).collect_vec(); + + let point_computations = chain![ + [ + "let x := mload(X_MPTR)", + "let omega := mload(OMEGA_MPTR)", + "let omega_inv := mload(OMEGA_INV_MPTR)", + "let x_pow_of_omega := mulmod(x, omega, r)" + ] + .map(str::to_string), + (1..=max_rot).flat_map(|rot| { + chain![ + points + .get(&rot) + .map(|point| format!("mstore({}, x_pow_of_omega)", point.ptr())), + (rot != max_rot) + .then(|| "x_pow_of_omega := mulmod(x_pow_of_omega, omega, r)".to_string()) + ] + }), + [ + format!("mstore({}, x)", points[&0].ptr()), + format!("x_pow_of_omega := mulmod(x, omega_inv, r)") + ], + (min_rot..0).rev().flat_map(|rot| { + chain![ + points + .get(&rot) + .map(|point| format!("mstore({}, x_pow_of_omega)", point.ptr())), + (rot != min_rot).then(|| { + "x_pow_of_omega := mulmod(x_pow_of_omega, omega_inv, r)".to_string() + }) + ] + }) + ] + .collect_vec(); + + let vanishing_computations = chain![ + ["let mu := mload(MU_MPTR)".to_string()], + { + let mptr = mu_minus_points.first_key_value().unwrap().1.ptr(); + let mptr_end = mptr + mu_minus_points.len(); + for_loop( + [ + format!("let mptr := {mptr}"), + format!("let mptr_end := {mptr_end}"), + format!("let point_mptr := {free_mptr}"), + ], + "lt(mptr, mptr_end)", + [ + "mptr := add(mptr, 0x20)", + "point_mptr := add(point_mptr, 0x20)", + ], + ["mstore(mptr, addmod(mu, sub(r, mload(point_mptr)), r))"], + ) + }, + ["let s".to_string()], + chain![ + [format!( + "s := {}", + mu_minus_points[sets[0].rots().first().unwrap()] + )], + chain![sets[0].rots().iter().skip(1)] + .map(|rot| { format!("s := mulmod(s, {}, r)", mu_minus_points[rot]) }), + [format!("mstore({}, s)", vanishing_0.ptr())], + ], + ["let diff".to_string()], + izip!(0.., &sets, &diffs).flat_map(|(set_idx, set, diff)| { + chain![ + [set.diffs() + .first() + .map(|rot| format!("diff := {}", mu_minus_points[rot])) + .unwrap_or_else(|| "diff := 1".to_string())], + chain![set.diffs().iter().skip(1)] + .map(|rot| { format!("diff := mulmod(diff, {}, r)", mu_minus_points[rot]) }), + [format!("mstore({}, diff)", diff.ptr())], + (set_idx == 0).then(|| format!("mstore({}, diff)", diff_0.ptr())), + ] + }) + ] + .collect_vec(); + + let coeff_computations = izip!(&sets, &coeffs) + .map(|(set, coeffs)| { + let coeff_points = set + .rots() + .iter() + .map(|rot| &point_vars[rot]) + .enumerate() + .map(|(i, rot_i)| { + set.rots() + .iter() + .map(|rot| &point_vars[rot]) + .enumerate() + .filter_map(|(j, rot_j)| (i != j).then_some((rot_i, rot_j))) + .collect_vec() + }) + .collect_vec(); + chain![ + set.rots() + .iter() + .map(|rot| format!("let {} := {}", &point_vars[rot], points[rot])), + ["let coeff".to_string()], + izip!(set.rots(), &coeff_points, coeffs).flat_map( + |(rot_i, coeff_points, coeff)| chain![ + [coeff_points + .first() + .map(|(point_i, point_j)| { + format!("coeff := addmod({point_i}, sub(r, {point_j}), r)") + }) + .unwrap_or_else(|| "coeff := 1".to_string())], + coeff_points.iter().skip(1).map(|(point_i, point_j)| { + let item = format!("addmod({point_i}, sub(r, {point_j}), r)"); + format!("coeff := mulmod(coeff, {item}, r)") + }), + [ + format!("coeff := mulmod(coeff, {}, r)", mu_minus_points[rot_i]), + format!("mstore({}, coeff)", coeff.ptr()) + ], + ] + ) + ] + .collect_vec() + }) + .collect_vec(); + + let normalized_coeff_computations = chain![ + [ + format!("success := batch_invert(success, 0, {first_batch_invert_end}, r)"), + format!("let diff_0_inv := {diff_0}"), + format!("mstore({}, diff_0_inv)", diffs[0].ptr()), + ], + for_loop( + [ + format!("let mptr := {}", diffs[0].ptr() + 1), + format!("let mptr_end := {}", diffs[0].ptr() + sets.len()), + ], + "lt(mptr, mptr_end)", + ["mptr := add(mptr, 0x20)"], + ["mstore(mptr, mulmod(mload(mptr), diff_0_inv, r))"], + ), + ] + .collect_vec(); + + let r_evals_computations = izip!(0.., &sets, &coeffs, &diffs, &r_evals).map( + |(set_idx, set, coeffs, set_coeff, r_eval)| { + let is_single_rot_set = set.rots().len() == 1; + chain![ + is_single_rot_set.then(|| format!("let coeff := {}", coeffs[0])), + ["let zeta := mload(ZETA_MPTR)", "let r_eval"].map(str::to_string), + if is_single_rot_set { + let evals = set.evals().iter().map(|evals| evals[0]).collect_vec(); + let eval_groups = group_backward_adjacent_words(evals.iter().rev().skip(1)); + chain![ + evals + .last() + .map(|eval| format!("r_eval := mulmod(coeff, {eval}, r)")), + eval_groups.iter().flat_map(|(loc, evals)| { + if evals.len() < 3 { + evals + .iter() + .flat_map(|eval| { + let item = format!("mulmod(coeff, {eval}, r)"); + [ + format!("r_eval := mulmod(r_eval, zeta, r)"), + format!("r_eval := addmod(r_eval, {item}, r)"), + ] + }) + .collect_vec() + } else { + assert_eq!(*loc, Location::Calldata); + let item = "mulmod(coeff, calldataload(cptr), r)"; + for_loop( + [ + format!("let cptr := {}", evals[0].ptr()), + format!("let cptr_end := {}", evals[0].ptr() - evals.len()), + ], + "lt(cptr_end, cptr)", + ["cptr := sub(cptr, 0x20)"], + [format!( + "r_eval := addmod(mulmod(r_eval, zeta, r), {item}, r)" + )], + ) + } + }) + ] + .collect_vec() + } else { + chain![set.evals().iter().enumerate().rev()] + .flat_map(|(idx, evals)| { + chain![ + izip!(evals, coeffs).map(|(eval, coeff)| { + let item = format!("mulmod({coeff}, {eval}, r)"); + format!("r_eval := addmod(r_eval, {item}, r)") + }), + (idx != 0).then(|| format!("r_eval := mulmod(r_eval, zeta, r)")), + ] + }) + .collect_vec() + }, + (set_idx != 0).then(|| format!("r_eval := mulmod(r_eval, {set_coeff}, r)")), + [format!("mstore({}, r_eval)", r_eval.ptr())], + ] + .collect_vec() + }, + ); + + let coeff_sums_computation = izip!(&coeffs, &sums).map(|(coeffs, sum)| { + let (coeff_0, rest_coeffs) = coeffs.split_first().unwrap(); + chain![ + [format!("let sum := {coeff_0}")], + rest_coeffs + .iter() + .map(|coeff_mptr| format!("sum := addmod(sum, {coeff_mptr}, r)")), + [format!("mstore({}, sum)", sum.ptr())], + ] + .collect_vec() + }); + + let r_eval_computations = chain![ + for_loop( + [ + format!("let mptr := 0x00"), + format!("let mptr_end := {second_batch_invert_end}"), + format!("let sum_mptr := {}", sums[0].ptr()), + ], + "lt(mptr, mptr_end)", + ["mptr := add(mptr, 0x20)", "sum_mptr := add(sum_mptr, 0x20)"], + ["mstore(mptr, mload(sum_mptr))"], + ), + [ + format!("success := batch_invert(success, 0, {second_batch_invert_end}, r)"), + format!( + "let r_eval := mulmod(mload({}), {}, r)", + second_batch_invert_end - 1, + r_evals.last().unwrap() + ) + ], + for_loop( + [ + format!("let sum_inv_mptr := {}", second_batch_invert_end - 2), + format!("let sum_inv_mptr_end := {second_batch_invert_end}"), + format!("let r_eval_mptr := {}", r_evals[r_evals.len() - 2].ptr()), + ], + "lt(sum_inv_mptr, sum_inv_mptr_end)", + [ + "sum_inv_mptr := sub(sum_inv_mptr, 0x20)", + "r_eval_mptr := sub(r_eval_mptr, 0x20)" + ], + [ + "r_eval := mulmod(r_eval, mload(NU_MPTR), r)", + "r_eval := addmod(r_eval, mulmod(mload(sum_inv_mptr), mload(r_eval_mptr), r), r)" + ], + ), + ["mstore(G1_SCALAR_MPTR, sub(r, r_eval))".to_string()], + ] + .collect_vec(); + + let pairing_input_computations = chain![ + ["let zeta := mload(ZETA_MPTR)", "let nu := mload(NU_MPTR)"].map(str::to_string), + izip!(0.., &sets, &diffs).flat_map(|(set_idx, set, set_coeff)| { + let is_first_set = set_idx == 0; + let is_last_set = set_idx == sets.len() - 1; + let ec_add = &format!("ec_add_{}", if is_first_set { "acc" } else { "tmp" }); + let ec_mul = &format!("ec_mul_{}", if is_first_set { "acc" } else { "tmp" }); + let acc_x = Ptr::memory(0x00) + if is_first_set { 0 } else { 4 }; + let acc_y = acc_x + 1; + let comm_groups = group_backward_adjacent_ec_points(set.comms().iter().rev().skip(1)); + + chain![ + set.comms() + .last() + .map(|comm| { + [ + format!("mstore({acc_x}, {})", comm.x()), + format!("mstore({acc_y}, {})", comm.y()), + ] + }) + .into_iter() + .flatten(), + comm_groups.into_iter().flat_map(move |(loc, comms)| { + if comms.len() < 3 { + comms + .iter() + .flat_map(|comm| { + let (x, y) = (comm.x(), comm.y()); + [ + format!("success := {ec_mul}(success, zeta)"), + format!("success := {ec_add}(success, {x}, {y})"), + ] + }) + .collect_vec() + } else { + let ptr = comms.first().unwrap().x().ptr(); + let ptr_end = ptr - 2 * comms.len(); + let x = Word::from(Ptr::new(loc, "ptr")); + let y = Word::from(Ptr::new(loc, "add(ptr, 0x20)")); + for_loop( + [ + format!("let ptr := {ptr}"), + format!("let ptr_end := {ptr_end}"), + ], + "lt(ptr_end, ptr)", + ["ptr := sub(ptr, 0x40)"], + [ + format!("success := {ec_mul}(success, zeta)"), + format!("success := {ec_add}(success, {x}, {y})"), + ], + ) + } + }), + (!is_first_set) + .then(|| { + let scalar = format!("mulmod(nu, {set_coeff}, r)"); + chain![ + [ + format!("success := ec_mul_tmp(success, {scalar})"), + format!("success := ec_add_acc(success, mload(0x80), mload(0xa0))"), + ], + (!is_last_set).then(|| format!("nu := mulmod(nu, mload(NU_MPTR), r)")) + ] + }) + .into_iter() + .flatten(), + ] + .collect_vec() + }), + [ + format!("mstore(0x80, mload(G1_X_MPTR))"), + format!("mstore(0xa0, mload(G1_Y_MPTR))"), + format!("success := ec_mul_tmp(success, mload(G1_SCALAR_MPTR))"), + format!("success := ec_add_acc(success, mload(0x80), mload(0xa0))"), + format!("mstore(0x80, {})", w.x()), + format!("mstore(0xa0, {})", w.y()), + format!("success := ec_mul_tmp(success, sub(r, {vanishing_0}))"), + format!("success := ec_add_acc(success, mload(0x80), mload(0xa0))"), + format!("mstore(0x80, {})", w_prime.x()), + format!("mstore(0xa0, {})", w_prime.y()), + format!("success := ec_mul_tmp(success, mload(MU_MPTR))"), + format!("success := ec_add_acc(success, mload(0x80), mload(0xa0))"), + format!("mstore(PAIRING_LHS_X_MPTR, mload(0x00))"), + format!("mstore(PAIRING_LHS_Y_MPTR, mload(0x20))"), + format!("mstore(PAIRING_RHS_X_MPTR, {})", w_prime.x()), + format!("mstore(PAIRING_RHS_Y_MPTR, {})", w_prime.y()), + ], + ] + .collect_vec(); + + chain![ + [point_computations, vanishing_computations], + coeff_computations, + [normalized_coeff_computations], + r_evals_computations, + coeff_sums_computation, + [r_eval_computations, pairing_input_computations], + ] + .collect_vec() +} + +#[derive(Debug)] +struct RotationSet { + rots: BTreeSet, + diffs: BTreeSet, + comms: Vec, + evals: Vec>, +} + +impl RotationSet { + fn rots(&self) -> &BTreeSet { + &self.rots + } + + fn diffs(&self) -> &BTreeSet { + &self.diffs + } + + fn comms(&self) -> &[EcPoint] { + &self.comms + } + + fn evals(&self) -> &[Vec] { + &self.evals + } +} + +fn rotation_sets(queries: &[Query]) -> (BTreeSet, Vec) { + let mut superset = BTreeSet::new(); + let comm_queries = queries.iter().fold( + Vec::<(EcPoint, BTreeMap)>::new(), + |mut comm_queries, query| { + superset.insert(query.rot); + if let Some(pos) = comm_queries + .iter() + .position(|(comm, _)| comm == &query.comm) + { + let (_, queries) = &mut comm_queries[pos]; + assert!(!queries.contains_key(&query.rot)); + queries.insert(query.rot, query.eval); + } else { + comm_queries.push((query.comm, BTreeMap::from_iter([(query.rot, query.eval)]))); + } + comm_queries + }, + ); + let superset = superset; + let sets = + comm_queries + .into_iter() + .fold(Vec::::new(), |mut sets, (comm, queries)| { + if let Some(pos) = sets + .iter() + .position(|set| itertools::equal(&set.rots, queries.keys())) + { + let set = &mut sets[pos]; + if !set.comms.contains(&comm) { + set.comms.push(comm); + set.evals.push(queries.into_values().collect_vec()); + } + } else { + let diffs = BTreeSet::from_iter( + superset + .iter() + .filter(|rot| !queries.contains_key(rot)) + .copied(), + ); + let set = RotationSet { + rots: BTreeSet::from_iter(queries.keys().copied()), + diffs, + comms: vec![comm], + evals: vec![queries.into_values().collect()], + }; + sets.push(set); + } + sets + }); + (superset, sets) +} diff --git a/crates/halo2-verifier/src/lib/codegen/pcs/gwc19.rs b/crates/halo2-verifier/src/lib/codegen/pcs/gwc19.rs new file mode 100644 index 00000000..a7686a0b --- /dev/null +++ b/crates/halo2-verifier/src/lib/codegen/pcs/gwc19.rs @@ -0,0 +1,300 @@ +#![allow(clippy::useless_format)] + +use std::collections::BTreeMap; + +use itertools::{chain, izip, Itertools}; + +use crate::codegen::{ + pcs::{queries, Query}, + util::{ + for_loop, group_backward_adjacent_ec_points, group_backward_adjacent_words, + ConstraintSystemMeta, Data, EcPoint, Location, Ptr, Word, + }, +}; + +pub(super) fn static_working_memory_size(meta: &ConstraintSystemMeta, _: &Data) -> usize { + 0x100 + meta.num_rotations * 0x40 +} + +pub(super) fn computations(meta: &ConstraintSystemMeta, data: &Data) -> Vec> { + let sets = rotation_sets(&queries(meta, data)); + let rots = sets.iter().map(|set| set.rot).collect_vec(); + let (min_rot, max_rot) = rots + .iter() + .copied() + .minmax() + .into_option() + .unwrap_or_default(); + + let ws = EcPoint::range(data.w_cptr).take(sets.len()).collect_vec(); + + let point_w_mptr = Ptr::memory(0x100); + let point_ws = izip!(rots, EcPoint::range(point_w_mptr)).collect::>(); + + let eval_computations = { + chain![ + [ + "let nu := mload(NU_MPTR)", + "let mu := mload(MU_MPTR)", + "let eval_acc", + "let eval_tmp", + ] + .map(str::to_string), + sets.iter().enumerate().rev().flat_map(|(set_idx, set)| { + let is_last_set = set_idx == sets.len() - 1; + let eval_acc = &format!("eval_{}", if is_last_set { "acc" } else { "tmp" }); + let eval_groups = group_backward_adjacent_words(set.evals().iter().rev().skip(1)); + + chain![ + set.evals() + .last() + .map(|eval| format!("{eval_acc} := {}", eval)), + eval_groups.iter().flat_map(|(loc, evals)| { + if evals.len() < 3 { + evals + .iter() + .map(|eval| { + format!( + "{eval_acc} := addmod(mulmod({eval_acc}, nu, r), {eval}, r)" + ) + }) + .collect_vec() + } else { + assert_eq!(*loc, Location::Calldata); + let eval = "calldataload(cptr)"; + for_loop( + [ + format!("let cptr := {}", evals[0].ptr()), + format!("let cptr_end := {}", evals[0].ptr() - evals.len()), + ], + "lt(cptr_end, cptr)", + ["cptr := sub(cptr, 0x20)"], + [format!( + "{eval_acc} := addmod(mulmod({eval_acc}, nu, r), {eval}, r)" + )], + ) + } + }), + (!is_last_set) + .then_some([ + "eval_acc := mulmod(eval_acc, mu, r)", + "eval_acc := addmod(eval_acc, eval_tmp, r)", + ]) + .into_iter() + .flatten() + .map(str::to_string), + ] + .collect_vec() + }), + ["mstore(G1_SCALAR_MPTR, sub(r, eval_acc))".to_string()], + ] + .collect_vec() + }; + + let point_computations = chain![ + [ + "let x := mload(X_MPTR)", + "let omega := mload(OMEGA_MPTR)", + "let omega_inv := mload(OMEGA_INV_MPTR)", + "let x_pow_of_omega := mulmod(x, omega, r)" + ] + .map(str::to_string), + (1..=max_rot).flat_map(|rot| { + chain![ + point_ws + .get(&rot) + .map(|point| format!("mstore({}, x_pow_of_omega)", point.x().ptr())), + (rot != max_rot) + .then(|| "x_pow_of_omega := mulmod(x_pow_of_omega, omega, r)".to_string()) + ] + }), + [ + format!("mstore({}, x)", point_ws[&0].x().ptr()), + format!("x_pow_of_omega := mulmod(x, omega_inv, r)") + ], + (min_rot..0).rev().flat_map(|rot| { + chain![ + point_ws + .get(&rot) + .map(|point| format!("mstore({}, x_pow_of_omega)", point.x().ptr())), + (rot != min_rot).then(|| { + "x_pow_of_omega := mulmod(x_pow_of_omega, omega_inv, r)".to_string() + }) + ] + }) + ] + .collect_vec(); + + let point_w_computations = for_loop( + [ + format!("let cptr := {}", data.w_cptr), + format!("let mptr := {point_w_mptr}"), + format!("let mptr_end := {}", point_w_mptr + 2 * sets.len()), + ], + "lt(mptr, mptr_end)".to_string(), + ["mptr := add(mptr, 0x40)", "cptr := add(cptr, 0x40)"].map(str::to_string), + [ + "mstore(0x00, calldataload(cptr))", + "mstore(0x20, calldataload(add(cptr, 0x20)))", + "success := ec_mul_acc(success, mload(mptr))", + "mstore(mptr, mload(0x00))", + "mstore(add(mptr, 0x20), mload(0x20))", + ] + .map(str::to_string), + ); + + let pairing_lhs_computations = chain![ + ["let nu := mload(NU_MPTR)", "let mu := mload(MU_MPTR)"].map(str::to_string), + sets.iter().enumerate().rev().flat_map(|(set_idx, set)| { + let is_last_set = set_idx == sets.len() - 1; + let ec_add = &format!("ec_add_{}", if is_last_set { "acc" } else { "tmp" }); + let ec_mul = &format!("ec_mul_{}", if is_last_set { "acc" } else { "tmp" }); + let acc_x = Ptr::memory(0x00) + if is_last_set { 0 } else { 4 }; + let acc_y = acc_x + 1; + let point_w = &point_ws[&set.rot]; + let comm_groups = group_backward_adjacent_ec_points(set.comms().iter().rev().skip(1)); + + chain![ + set.comms() + .last() + .map(|comm| { + [ + format!("mstore({acc_x}, {})", comm.x()), + format!("mstore({acc_y}, {})", comm.y()), + ] + }) + .into_iter() + .flatten(), + comm_groups.into_iter().flat_map(move |(loc, comms)| { + if comms.len() < 3 { + comms + .iter() + .flat_map(|comm| { + let (x, y) = (comm.x(), comm.y()); + [ + format!("success := {ec_mul}(success, nu)"), + format!("success := {ec_add}(success, {x}, {y})"), + ] + }) + .collect_vec() + } else { + let ptr = comms.first().unwrap().x().ptr(); + let ptr_end = ptr - 2 * comms.len(); + let x = Word::from(Ptr::new(loc, "ptr")); + let y = Word::from(Ptr::new(loc, "add(ptr, 0x20)")); + for_loop( + [ + format!("let ptr := {ptr}"), + format!("let ptr_end := {ptr_end}"), + ], + "lt(ptr_end, ptr)", + ["ptr := sub(ptr, 0x40)".to_string()], + [ + format!("success := {ec_mul}(success, nu)"), + format!("success := {ec_add}(success, {x}, {y})"), + ], + ) + } + }), + [format!( + "success := {ec_add}(success, {}, {})", + point_w.x(), + point_w.y() + )], + (!is_last_set) + .then_some([ + "success := ec_mul_acc(success, mu)", + "success := ec_add_acc(success, mload(0x80), mload(0xa0))", + ]) + .into_iter() + .flatten() + .map(str::to_string), + ] + .collect_vec() + }), + [ + "mstore(0x80, mload(G1_X_MPTR))", + "mstore(0xa0, mload(G1_Y_MPTR))", + "success := ec_mul_tmp(success, mload(G1_SCALAR_MPTR))", + "success := ec_add_acc(success, mload(0x80), mload(0xa0))", + "mstore(PAIRING_LHS_X_MPTR, mload(0x00))", + "mstore(PAIRING_LHS_Y_MPTR, mload(0x20))", + ] + .map(str::to_string), + ] + .collect_vec(); + + let pairing_rhs_computations = chain![ + [ + format!("let mu := mload(MU_MPTR)"), + format!("mstore(0x00, {})", ws.last().unwrap().x()), + format!("mstore(0x20, {})", ws.last().unwrap().y()), + ], + ws.iter() + .nth_back(1) + .map(|w_second_last| { + let x = "calldataload(cptr)"; + let y = "calldataload(add(cptr, 0x20))"; + for_loop( + [ + format!("let cptr := {}", w_second_last.x().ptr()), + format!("let cptr_end := {}", ws[0].x().ptr() - 1), + ], + "lt(cptr_end, cptr)", + ["cptr := sub(cptr, 0x40)"], + [ + format!("success := ec_mul_acc(success, mu)"), + format!("success := ec_add_acc(success, {x}, {y})"), + ], + ) + }) + .into_iter() + .flatten(), + [ + format!("mstore(PAIRING_RHS_X_MPTR, mload(0x00))"), + format!("mstore(PAIRING_RHS_Y_MPTR, mload(0x20))"), + ], + ] + .collect_vec(); + + vec![ + eval_computations, + point_computations, + point_w_computations, + pairing_lhs_computations, + pairing_rhs_computations, + ] +} + +#[derive(Debug)] +struct RotationSet { + rot: i32, + comms: Vec, + evals: Vec, +} + +impl RotationSet { + fn comms(&self) -> &[EcPoint] { + &self.comms + } + + fn evals(&self) -> &[Word] { + &self.evals + } +} + +fn rotation_sets(queries: &[Query]) -> Vec { + queries.iter().fold(Vec::new(), |mut sets, query| { + if let Some(pos) = sets.iter().position(|set| set.rot == query.rot) { + sets[pos].comms.push(query.comm); + sets[pos].evals.push(query.eval); + } else { + sets.push(RotationSet { + rot: query.rot, + comms: vec![query.comm], + evals: vec![query.eval], + }); + } + sets + }) +} diff --git a/crates/halo2-verifier/src/lib/codegen/template.rs b/crates/halo2-verifier/src/lib/codegen/template.rs new file mode 100644 index 00000000..91966e54 --- /dev/null +++ b/crates/halo2-verifier/src/lib/codegen/template.rs @@ -0,0 +1,86 @@ +use std::fmt; + +use askama::{Error, Template}; +use ruint::aliases::U256; + +use crate::codegen::{ + pcs::BatchOpenScheme::{self, Bdfg21, Gwc19}, + util::Ptr, +}; + +#[derive(Template)] +#[template(path = "Halo2VerifyingKey.sol")] +pub(crate) struct Halo2VerifyingKey { + pub(crate) constants: Vec<(&'static str, U256)>, + pub(crate) fixed_comms: Vec<(U256, U256)>, + pub(crate) permutation_comms: Vec<(U256, U256)>, +} + +impl Halo2VerifyingKey { + pub(crate) fn len(&self) -> usize { + (self.constants.len() * 0x20) + + (self.fixed_comms.len() + self.permutation_comms.len()) * 0x40 + } +} + +#[derive(Template)] +#[template(path = "Halo2Verifier.sol")] +pub(crate) struct Halo2Verifier { + pub(crate) scheme: BatchOpenScheme, + pub(crate) embedded_vk: Option, + pub(crate) vk_len: usize, + pub(crate) proof_len: usize, + pub(crate) vk_mptr: Ptr, + pub(crate) challenge_mptr: Ptr, + pub(crate) theta_mptr: Ptr, + pub(crate) proof_cptr: Ptr, + pub(crate) quotient_comm_cptr: Ptr, + pub(crate) num_neg_lagranges: usize, + pub(crate) num_advices: Vec, + pub(crate) num_challenges: Vec, + pub(crate) num_rotations: usize, + pub(crate) num_evals: usize, + pub(crate) num_quotients: usize, + pub(crate) quotient_eval_numer_computations: Vec>, + pub(crate) pcs_computations: Vec>, +} + +impl Halo2VerifyingKey { + pub(crate) fn render(&self, writer: &mut impl fmt::Write) -> Result<(), fmt::Error> { + self.render_into(writer).map_err(|err| match err { + Error::Fmt(err) => err, + _ => unreachable!(), + }) + } +} + +impl Halo2Verifier { + pub(crate) fn render(&self, writer: &mut impl fmt::Write) -> Result<(), fmt::Error> { + self.render_into(writer).map_err(|err| match err { + Error::Fmt(err) => err, + _ => unreachable!(), + }) + } +} + +mod filters { + use std::fmt::LowerHex; + + pub fn hex(value: impl LowerHex) -> ::askama::Result { + let value = format!("{value:x}"); + Ok(if value.len() % 2 == 1 { + format!("0x0{value}") + } else { + format!("0x{value}") + }) + } + + pub fn hex_padded(value: impl LowerHex, pad: usize) -> ::askama::Result { + let string = format!("0x{value:0pad$x}"); + if string == "0x0" { + Ok(format!("0x{}", "0".repeat(pad))) + } else { + Ok(string) + } + } +} diff --git a/crates/halo2-verifier/src/lib/codegen/util.rs b/crates/halo2-verifier/src/lib/codegen/util.rs new file mode 100644 index 00000000..83345a75 --- /dev/null +++ b/crates/halo2-verifier/src/lib/codegen/util.rs @@ -0,0 +1,660 @@ +use std::{ + borrow::Borrow, + collections::HashMap, + fmt::{self, Display, Formatter}, + ops::{Add, Sub}, +}; + +use halo2_proofs::{ + halo2curves::{bn256, bn256::Fq, ff::PrimeField, CurveAffine}, + plonk::{Any, Column, ConstraintSystem}, +}; +use itertools::{chain, izip, Itertools}; +use ruint::aliases::U256; +use shielder_rust_sdk::conversion::field_to_u256; + +use crate::codegen::{ + template::Halo2VerifyingKey, + BatchOpenScheme::{self, Bdfg21, Gwc19}, +}; + +#[derive(Debug)] +pub(crate) struct ConstraintSystemMeta { + pub(crate) num_fixeds: usize, + pub(crate) permutation_columns: Vec>, + pub(crate) permutation_chunk_len: usize, + pub(crate) num_lookup_permuteds: usize, + pub(crate) num_permutation_zs: usize, + pub(crate) num_lookup_zs: usize, + pub(crate) num_quotients: usize, + pub(crate) advice_queries: Vec<(usize, i32)>, + pub(crate) fixed_queries: Vec<(usize, i32)>, + pub(crate) num_rotations: usize, + pub(crate) num_evals: usize, + pub(crate) num_user_advices: Vec, + pub(crate) num_user_challenges: Vec, + pub(crate) advice_indices: Vec, + pub(crate) challenge_indices: Vec, + pub(crate) rotation_last: i32, +} + +impl ConstraintSystemMeta { + pub(crate) fn new(cs: &ConstraintSystem) -> Self { + let num_fixeds = cs.num_fixed_columns(); + let permutation_columns = cs.permutation().get_columns(); + let permutation_chunk_len = cs.degree() - 2; + let num_lookup_permuteds = 2 * cs.lookups().len(); + let num_permutation_zs = cs + .permutation() + .get_columns() + .chunks(cs.degree() - 2) + .count(); + let num_lookup_zs = cs.lookups().len(); + let num_quotients = cs.degree() - 1; + let advice_queries = cs + .advice_queries() + .iter() + .map(|(column, rotation)| (column.index(), rotation.0)) + .collect_vec(); + let fixed_queries = cs + .fixed_queries() + .iter() + .map(|(column, rotation)| (column.index(), rotation.0)) + .collect_vec(); + let num_evals = advice_queries.len() + + fixed_queries.len() + + 1 + + cs.permutation().get_columns().len() + + (3 * num_permutation_zs - 1) + + 5 * cs.lookups().len(); + let num_phase = *cs.advice_column_phase().iter().max().unwrap_or(&0) as usize + 1; + // Indices of advice and challenge are not same as their position in calldata/memory, + // because we support multiple phases, we need to remap them and find their actual indices. + let remapping = |phase: Vec| { + let nums = phase.iter().fold(vec![0; num_phase], |mut nums, phase| { + nums[*phase as usize] += 1; + nums + }); + let offsets = nums + .iter() + .take(num_phase - 1) + .fold(vec![0], |mut offsets, n| { + offsets.push(offsets.last().unwrap() + n); + offsets + }); + let index = phase + .iter() + .scan(offsets, |state, phase| { + let index = state[*phase as usize]; + state[*phase as usize] += 1; + Some(index) + }) + .collect::>(); + (nums, index) + }; + let (num_user_advices, advice_indices) = remapping(cs.advice_column_phase()); + let (num_user_challenges, challenge_indices) = remapping(cs.challenge_phase()); + let rotation_last = -(cs.blinding_factors() as i32 + 1); + let num_rotations = chain![ + advice_queries.iter().map(|query| query.1), + fixed_queries.iter().map(|query| query.1), + (num_permutation_zs > 0) + .then_some([0, 1]) + .into_iter() + .flatten(), + (num_permutation_zs > 1).then_some(rotation_last), + (num_lookup_zs > 0) + .then_some([-1, 0, 1]) + .into_iter() + .flatten(), + ] + .unique() + .count(); + Self { + num_fixeds, + permutation_columns, + permutation_chunk_len, + num_lookup_permuteds, + num_permutation_zs, + num_lookup_zs, + num_quotients, + advice_queries, + fixed_queries, + num_evals, + num_rotations, + num_user_advices, + num_user_challenges, + advice_indices, + challenge_indices, + rotation_last, + } + } + + pub(crate) fn num_advices(&self) -> Vec { + chain![ + self.num_user_advices.iter().cloned(), + (self.num_lookup_permuteds != 0).then_some(self.num_lookup_permuteds), // lookup permuted + [ + self.num_permutation_zs + self.num_lookup_zs + 1, // permutation and lookup grand products, random + self.num_quotients, // quotients + ], + ] + .collect() + } + + pub(crate) fn num_challenges(&self) -> Vec { + let mut num_challenges = self.num_user_challenges.clone(); + // If there is no lookup used, merge also beta and gamma into the last user phase, to avoid + // squeezing challenge from nothing. + // Otherwise, merge theta into last user phase since they are originally adjacent. + if self.num_lookup_permuteds == 0 { + *num_challenges.last_mut().unwrap() += 3; // theta, beta, gamma + num_challenges.extend([ + 1, // y + 1, // x + ]); + } else { + *num_challenges.last_mut().unwrap() += 1; // theta + num_challenges.extend([ + 2, // beta, gamma + 1, // y + 1, // x + ]); + } + num_challenges + } + + pub(crate) fn num_permutations(&self) -> usize { + self.permutation_columns.len() + } + + pub(crate) fn num_lookups(&self) -> usize { + self.num_lookup_zs + } + + pub(crate) fn proof_len(&self, scheme: BatchOpenScheme) -> usize { + self.num_advices().iter().sum::() * 0x40 + + self.num_evals * 0x20 + + self.batch_open_proof_len(scheme) + } + + pub(crate) fn batch_open_proof_len(&self, scheme: BatchOpenScheme) -> usize { + (match scheme { + Bdfg21 => 2, + Gwc19 => self.num_rotations, + }) * 0x40 + } +} + +#[derive(Debug)] +pub(crate) struct Data { + pub(crate) challenge_mptr: Ptr, + pub(crate) theta_mptr: Ptr, + + pub(crate) quotient_comm_cptr: Ptr, + pub(crate) w_cptr: Ptr, + + pub(crate) fixed_comms: Vec, + pub(crate) permutation_comms: HashMap, EcPoint>, + pub(crate) advice_comms: Vec, + pub(crate) lookup_permuted_comms: Vec<(EcPoint, EcPoint)>, + pub(crate) permutation_z_comms: Vec, + pub(crate) lookup_z_comms: Vec, + pub(crate) random_comm: EcPoint, + + pub(crate) challenges: Vec, + + pub(crate) instance_eval: Word, + pub(crate) advice_evals: HashMap<(usize, i32), Word>, + pub(crate) fixed_evals: HashMap<(usize, i32), Word>, + pub(crate) random_eval: Word, + pub(crate) permutation_evals: HashMap, Word>, + pub(crate) permutation_z_evals: Vec<(Word, Word, Word)>, + pub(crate) lookup_evals: Vec<(Word, Word, Word, Word, Word)>, + + pub(crate) computed_quotient_comm: EcPoint, + pub(crate) computed_quotient_eval: Word, +} + +impl Data { + pub(crate) fn new( + meta: &ConstraintSystemMeta, + vk: &Halo2VerifyingKey, + vk_mptr: Ptr, + proof_cptr: Ptr, + ) -> Self { + let fixed_comm_mptr = vk_mptr + vk.constants.len(); + let permutation_comm_mptr = fixed_comm_mptr + 2 * vk.fixed_comms.len(); + let challenge_mptr = permutation_comm_mptr + 2 * vk.permutation_comms.len(); + let theta_mptr = challenge_mptr + meta.challenge_indices.len(); + + let advice_comm_start = proof_cptr; + let lookup_permuted_comm_start = advice_comm_start + 2 * meta.advice_indices.len(); + let permutation_z_comm_start = lookup_permuted_comm_start + 2 * meta.num_lookup_permuteds; + let lookup_z_comm_start = permutation_z_comm_start + 2 * meta.num_permutation_zs; + let random_comm_start = lookup_z_comm_start + 2 * meta.num_lookup_zs; + let quotient_comm_start = random_comm_start + 2; + + let eval_cptr = quotient_comm_start + 2 * meta.num_quotients; + let advice_eval_cptr = eval_cptr; + let fixed_eval_cptr = advice_eval_cptr + meta.advice_queries.len(); + let random_eval_cptr = fixed_eval_cptr + meta.fixed_queries.len(); + let permutation_eval_cptr = random_eval_cptr + 1; + let permutation_z_eval_cptr = permutation_eval_cptr + meta.num_permutations(); + let lookup_eval_cptr = permutation_z_eval_cptr + 3 * meta.num_permutation_zs - 1; + let w_cptr = lookup_eval_cptr + 5 * meta.num_lookups(); + + let fixed_comms = EcPoint::range(fixed_comm_mptr) + .take(meta.num_fixeds) + .collect(); + let permutation_comms = izip!( + meta.permutation_columns.iter().cloned(), + EcPoint::range(permutation_comm_mptr) + ) + .collect(); + let advice_comms = meta + .advice_indices + .iter() + .map(|idx| advice_comm_start + 2 * idx) + .map_into() + .collect(); + let lookup_permuted_comms = EcPoint::range(lookup_permuted_comm_start) + .take(meta.num_lookup_permuteds) + .tuples() + .collect(); + let permutation_z_comms = EcPoint::range(permutation_z_comm_start) + .take(meta.num_permutation_zs) + .collect(); + let lookup_z_comms = EcPoint::range(lookup_z_comm_start) + .take(meta.num_lookup_zs) + .collect(); + let random_comm = random_comm_start.into(); + let computed_quotient_comm = EcPoint::new( + Ptr::memory("QUOTIENT_X_MPTR"), + Ptr::memory("QUOTIENT_Y_MPTR"), + ); + + let challenges = meta + .challenge_indices + .iter() + .map(|idx| challenge_mptr + *idx) + .map_into() + .collect_vec(); + let instance_eval = Ptr::memory("INSTANCE_EVAL_MPTR").into(); + let advice_evals = izip!( + meta.advice_queries.iter().cloned(), + Word::range(advice_eval_cptr) + ) + .collect(); + let fixed_evals = izip!( + meta.fixed_queries.iter().cloned(), + Word::range(fixed_eval_cptr) + ) + .collect(); + let random_eval = random_eval_cptr.into(); + let permutation_evals = izip!( + meta.permutation_columns.iter().cloned(), + Word::range(permutation_eval_cptr) + ) + .collect(); + let permutation_z_evals = Word::range(permutation_z_eval_cptr) + .take(3 * meta.num_permutation_zs) + .tuples() + .collect_vec(); + let lookup_evals = Word::range(lookup_eval_cptr) + .take(5 * meta.num_lookup_zs) + .tuples() + .collect_vec(); + let computed_quotient_eval = Ptr::memory("QUOTIENT_EVAL_MPTR").into(); + + Self { + challenge_mptr, + theta_mptr, + quotient_comm_cptr: quotient_comm_start, + w_cptr, + + fixed_comms, + permutation_comms, + advice_comms, + lookup_permuted_comms, + permutation_z_comms, + lookup_z_comms, + random_comm, + computed_quotient_comm, + + challenges, + + instance_eval, + advice_evals, + fixed_evals, + permutation_evals, + permutation_z_evals, + lookup_evals, + random_eval, + computed_quotient_eval, + } + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub(crate) enum Location { + Calldata, + Memory, +} + +impl Location { + fn opcode(&self) -> &'static str { + match self { + Location::Calldata => "calldataload", + Location::Memory => "mload", + } + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub(crate) enum Value { + Integer(usize), + Identifier(&'static str), +} + +impl Value { + pub(crate) fn is_integer(&self) -> bool { + match self { + Value::Integer(_) => true, + Value::Identifier(_) => false, + } + } + + pub(crate) fn as_usize(&self) -> usize { + match self { + Value::Integer(int) => *int, + Value::Identifier(_) => unreachable!(), + } + } +} + +impl Default for Value { + fn default() -> Self { + Self::Integer(0) + } +} + +impl From<&'static str> for Value { + fn from(ident: &'static str) -> Self { + Value::Identifier(ident) + } +} + +impl From for Value { + fn from(int: usize) -> Self { + Value::Integer(int) + } +} + +impl Display for Value { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + match self { + Value::Integer(int) => { + let hex = format!("{int:x}"); + if hex.len() % 2 == 1 { + write!(f, "0x0{hex}") + } else { + write!(f, "0x{hex}") + } + } + Value::Identifier(ident) => { + write!(f, "{ident}") + } + } + } +} + +impl Add for Value { + type Output = Value; + + fn add(self, rhs: usize) -> Self::Output { + (self.as_usize() + rhs * 0x20).into() + } +} + +impl Sub for Value { + type Output = Value; + + fn sub(self, rhs: usize) -> Self::Output { + (self.as_usize() - rhs * 0x20).into() + } +} + +/// `Ptr` points to a EVM word at either calldata or memory. +/// +/// When adding or subtracting it by 1, its value moves by 32 and points to next/previous EVM word. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub(crate) struct Ptr { + loc: Location, + value: Value, +} + +impl Ptr { + pub(crate) fn new(loc: Location, value: impl Into) -> Self { + Self { + loc, + value: value.into(), + } + } + + pub(crate) fn memory(value: impl Into) -> Self { + Self::new(Location::Memory, value.into()) + } + + pub(crate) fn calldata(value: impl Into) -> Self { + Self::new(Location::Calldata, value.into()) + } + + pub(crate) fn loc(&self) -> Location { + self.loc + } + + pub(crate) fn value(&self) -> Value { + self.value + } +} + +impl Display for Ptr { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.value) + } +} + +impl Add for Ptr { + type Output = Ptr; + + fn add(mut self, rhs: usize) -> Self::Output { + self.value = self.value + rhs; + self + } +} + +impl Sub for Ptr { + type Output = Ptr; + + fn sub(mut self, rhs: usize) -> Self::Output { + self.value = self.value - rhs; + self + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub(crate) struct Word(Ptr); + +impl Word { + pub(crate) fn range(word: impl Into) -> impl Iterator { + let ptr = word.into().ptr(); + (0..).map(move |idx| ptr + idx).map_into() + } + + pub(crate) fn ptr(&self) -> Ptr { + self.0 + } + + pub(crate) fn loc(&self) -> Location { + self.0.loc() + } +} + +impl Display for Word { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "{}({})", self.0.loc.opcode(), self.0.value) + } +} + +impl From for Word { + fn from(ptr: Ptr) -> Self { + Self(ptr) + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub(crate) struct EcPoint { + x: Word, + y: Word, +} + +impl EcPoint { + pub(crate) fn new(x: impl Into, y: impl Into) -> Self { + Self { + x: x.into(), + y: y.into(), + } + } + + pub(crate) fn range(ec_point: impl Into) -> impl Iterator { + let ptr = ec_point.into().x.ptr(); + (0..).map(move |idx| ptr + 2 * idx).map_into() + } + + pub(crate) fn loc(&self) -> Location { + self.x.ptr().loc() + } + + pub(crate) fn x(&self) -> Word { + self.x + } + + pub(crate) fn y(&self) -> Word { + self.y + } +} + +impl From for EcPoint { + fn from(ptr: Ptr) -> Self { + Self::new(ptr, ptr + 1) + } +} + +/// Add indention to given lines by `4 * N` spaces. +pub(crate) fn indent( + lines: impl IntoIterator>, +) -> Vec { + lines + .into_iter() + .map(|line| format!("{}{}", " ".repeat(N * 4), line.into())) + .collect() +} + +/// Create a code block for given lines with indention. +/// +/// If `PACKED` is true, single line code block will be packed into single line. +pub(crate) fn code_block( + lines: impl IntoIterator>, +) -> Vec { + let lines = lines.into_iter().map_into().collect_vec(); + let bracket_indent = " ".repeat((N - 1) * 4); + match lines.len() { + 0 => vec![format!("{bracket_indent}{{}}")], + 1 if PACKED => vec![format!("{bracket_indent}{{ {} }}", lines[0])], + _ => chain![ + [format!("{bracket_indent}{{")], + indent::(lines), + [format!("{bracket_indent}}}")], + ] + .collect(), + } +} + +/// Create a for loop with proper indention. +pub(crate) fn for_loop( + initialization: impl IntoIterator>, + condition: impl Into, + advancement: impl IntoIterator>, + body: impl IntoIterator>, +) -> Vec { + chain![ + ["for".to_string()], + code_block::<2, true>(initialization), + indent::<1>([condition.into()]), + code_block::<2, true>(advancement), + code_block::<1, false>(body), + ] + .collect() +} + +pub(crate) fn group_backward_adjacent_words<'a>( + words: impl IntoIterator, +) -> Vec<(Location, Vec<&'a Word>)> { + words.into_iter().fold(Vec::new(), |mut word_groups, word| { + if let Some(last_group) = word_groups.last_mut() { + let last_word = **last_group.1.last().unwrap(); + if last_group.0 == word.loc() + && last_word.ptr().value().is_integer() + && last_word.ptr() - 1 == word.ptr() + { + last_group.1.push(word) + } else { + word_groups.push((word.loc(), vec![word])) + } + word_groups + } else { + vec![(word.loc(), vec![word])] + } + }) +} + +pub(crate) fn group_backward_adjacent_ec_points<'a>( + ec_point: impl IntoIterator, +) -> Vec<(Location, Vec<&'a EcPoint>)> { + ec_point + .into_iter() + .fold(Vec::new(), |mut ec_point_groups, ec_point| { + if let Some(last_group) = ec_point_groups.last_mut() { + let last_ec_point = **last_group.1.last().unwrap(); + if last_group.0 == ec_point.loc() + && last_ec_point.x().ptr().value().is_integer() + && last_ec_point.x().ptr() - 2 == ec_point.x().ptr() + { + last_group.1.push(ec_point) + } else { + ec_point_groups.push((ec_point.loc(), vec![ec_point])) + } + ec_point_groups + } else { + vec![(ec_point.loc(), vec![ec_point])] + } + }) +} + +pub(crate) fn g1_to_u256s(ec_point: impl Borrow) -> [U256; 2] { + let coords = ec_point.borrow().coordinates().unwrap(); + [coords.x(), coords.y()].map(field_to_u256::) +} + +pub(crate) fn g2_to_u256s(ec_point: impl Borrow) -> [U256; 4] { + let coords = ec_point.borrow().coordinates().unwrap(); + let x = coords.x().to_repr(); + let y = coords.y().to_repr(); + [ + U256::try_from_le_slice(&x.as_ref()[0x20..]).unwrap(), + U256::try_from_le_slice(&x.as_ref()[..0x20]).unwrap(), + U256::try_from_le_slice(&y.as_ref()[0x20..]).unwrap(), + U256::try_from_le_slice(&y.as_ref()[..0x20]).unwrap(), + ] +} diff --git a/crates/halo2-verifier/src/lib/lib.rs b/crates/halo2-verifier/src/lib/lib.rs new file mode 100644 index 00000000..bf362ce3 --- /dev/null +++ b/crates/halo2-verifier/src/lib/lib.rs @@ -0,0 +1,12 @@ +//! Solidity verifier generator for [`halo2`] proof with KZG polynomial commitment scheme on BN254. +//! +//! [`halo2`]: http://github.com/privacy-scaling-explorations/halo2 + +#![deny(missing_docs)] +#![deny(missing_debug_implementations)] +#![deny(rustdoc::broken_intra_doc_links)] + +mod codegen; +pub mod verifier_contract; + +pub use codegen::{AccumulatorEncoding, BatchOpenScheme, SolidityGenerator}; diff --git a/crates/halo2-verifier/src/lib/verifier_contract.rs b/crates/halo2-verifier/src/lib/verifier_contract.rs new file mode 100644 index 00000000..fb14d89a --- /dev/null +++ b/crates/halo2-verifier/src/lib/verifier_contract.rs @@ -0,0 +1,23 @@ +#![allow(missing_docs)] +use alloy_primitives::Address; +use alloy_sol_types::{private::Bytes, sol, SolCall}; +use halo2_proofs::halo2curves::bn256::Fr; +use shielder_rust_sdk::conversion::field_to_u256; + +sol! { + function verifyProof( + address vk, + bytes calldata proof, + uint256[] calldata instances + ) public returns (bool); +} + +/// Encode proof into calldata to invoke `Halo2Verifier.verifyProof`. +pub fn encode_calldata(vk: Address, proof: &[u8], instances: &[Fr]) -> Vec { + verifyProofCall { + vk, + proof: Bytes::from(proof.to_vec()), + instances: instances.iter().map(field_to_u256::).collect(), + } + .abi_encode() +} diff --git a/crates/halo2-verifier/templates/Halo2Verifier.sol b/crates/halo2-verifier/templates/Halo2Verifier.sol new file mode 100644 index 00000000..96568abb --- /dev/null +++ b/crates/halo2-verifier/templates/Halo2Verifier.sol @@ -0,0 +1,572 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.26; + +/* @dev: linter does not understand inline assembly */ +/* solhint-disable no-unused-vars */ +contract Halo2Verifier { + uint256 internal constant PROOF_LEN_CPTR = {{ proof_cptr - 1 }}; + uint256 internal constant PROOF_CPTR = {{ proof_cptr }}; + uint256 internal constant NUM_INSTANCE_CPTR = {{ proof_cptr + (proof_len / 32) }}; + uint256 internal constant INSTANCE_CPTR = {{ proof_cptr + (proof_len / 32) + 1 }}; + + uint256 internal constant FIRST_QUOTIENT_X_CPTR = {{ quotient_comm_cptr }}; + uint256 internal constant LAST_QUOTIENT_X_CPTR = {{ quotient_comm_cptr + 2 * (num_quotients - 1) }}; + + uint256 internal constant VK_MPTR = {{ vk_mptr }}; + uint256 internal constant VK_DIGEST_MPTR = {{ vk_mptr }}; + uint256 internal constant NUM_INSTANCES_MPTR = {{ vk_mptr + 1 }}; + uint256 internal constant K_MPTR = {{ vk_mptr + 2 }}; + uint256 internal constant N_INV_MPTR = {{ vk_mptr + 3 }}; + uint256 internal constant OMEGA_MPTR = {{ vk_mptr + 4 }}; + uint256 internal constant OMEGA_INV_MPTR = {{ vk_mptr + 5 }}; + uint256 internal constant OMEGA_INV_TO_L_MPTR = {{ vk_mptr + 6 }}; + uint256 internal constant HAS_ACCUMULATOR_MPTR = {{ vk_mptr + 7 }}; + uint256 internal constant ACC_OFFSET_MPTR = {{ vk_mptr + 8 }}; + uint256 internal constant NUM_ACC_LIMBS_MPTR = {{ vk_mptr + 9 }}; + uint256 internal constant NUM_ACC_LIMB_BITS_MPTR = {{ vk_mptr + 10 }}; + uint256 internal constant G1_X_MPTR = {{ vk_mptr + 11 }}; + uint256 internal constant G1_Y_MPTR = {{ vk_mptr + 12 }}; + uint256 internal constant G2_X_1_MPTR = {{ vk_mptr + 13 }}; + uint256 internal constant G2_X_2_MPTR = {{ vk_mptr + 14 }}; + uint256 internal constant G2_Y_1_MPTR = {{ vk_mptr + 15 }}; + uint256 internal constant G2_Y_2_MPTR = {{ vk_mptr + 16 }}; + uint256 internal constant NEG_S_G2_X_1_MPTR = {{ vk_mptr + 17 }}; + uint256 internal constant NEG_S_G2_X_2_MPTR = {{ vk_mptr + 18 }}; + uint256 internal constant NEG_S_G2_Y_1_MPTR = {{ vk_mptr + 19 }}; + uint256 internal constant NEG_S_G2_Y_2_MPTR = {{ vk_mptr + 20 }}; + + uint256 internal constant CHALLENGE_MPTR = {{ challenge_mptr }}; + + uint256 internal constant THETA_MPTR = {{ theta_mptr }}; + uint256 internal constant BETA_MPTR = {{ theta_mptr + 1 }}; + uint256 internal constant GAMMA_MPTR = {{ theta_mptr + 2 }}; + uint256 internal constant Y_MPTR = {{ theta_mptr + 3 }}; + uint256 internal constant X_MPTR = {{ theta_mptr + 4 }}; + {%- match scheme %} + {%- when Bdfg21 %} + uint256 internal constant ZETA_MPTR = {{ theta_mptr + 5 }}; + uint256 internal constant NU_MPTR = {{ theta_mptr + 6 }}; + uint256 internal constant MU_MPTR = {{ theta_mptr + 7 }}; + {%- when Gwc19 %} + uint256 internal constant NU_MPTR = {{ theta_mptr + 5 }}; + uint256 internal constant MU_MPTR = {{ theta_mptr + 6 }}; + {%- endmatch %} + + uint256 internal constant ACC_LHS_X_MPTR = {{ theta_mptr + 8 }}; + uint256 internal constant ACC_LHS_Y_MPTR = {{ theta_mptr + 9 }}; + uint256 internal constant ACC_RHS_X_MPTR = {{ theta_mptr + 10 }}; + uint256 internal constant ACC_RHS_Y_MPTR = {{ theta_mptr + 11 }}; + uint256 internal constant X_N_MPTR = {{ theta_mptr + 12 }}; + uint256 internal constant X_N_MINUS_1_INV_MPTR = {{ theta_mptr + 13 }}; + uint256 internal constant L_LAST_MPTR = {{ theta_mptr + 14 }}; + uint256 internal constant L_BLIND_MPTR = {{ theta_mptr + 15 }}; + uint256 internal constant L_0_MPTR = {{ theta_mptr + 16 }}; + uint256 internal constant INSTANCE_EVAL_MPTR = {{ theta_mptr + 17 }}; + uint256 internal constant QUOTIENT_EVAL_MPTR = {{ theta_mptr + 18 }}; + uint256 internal constant QUOTIENT_X_MPTR = {{ theta_mptr + 19 }}; + uint256 internal constant QUOTIENT_Y_MPTR = {{ theta_mptr + 20 }}; + uint256 internal constant G1_SCALAR_MPTR = {{ theta_mptr + 21 }}; + uint256 internal constant PAIRING_LHS_X_MPTR = {{ theta_mptr + 22 }}; + uint256 internal constant PAIRING_LHS_Y_MPTR = {{ theta_mptr + 23 }}; + uint256 internal constant PAIRING_RHS_X_MPTR = {{ theta_mptr + 24 }}; + uint256 internal constant PAIRING_RHS_Y_MPTR = {{ theta_mptr + 25 }}; + + function verifyProof( + {%- match self.embedded_vk %} + {%- when None %} + address vk, + {%- else %} + {%- endmatch %} + bytes calldata proof, + uint256[] calldata instances + ) public returns (bool) { + assembly ("memory-safe") { + // Read EC point (x, y) at (proof_cptr, proof_cptr + 0x20), + // and check if the point is on affine plane, + // and store them in (hash_mptr, hash_mptr + 0x20). + // Return updated (success, proof_cptr, hash_mptr). + function read_ec_point(success, proof_cptr, hash_mptr, q) -> ret0, ret1, ret2 { + let x := calldataload(proof_cptr) + let y := calldataload(add(proof_cptr, 0x20)) + ret0 := and(success, lt(x, q)) + ret0 := and(ret0, lt(y, q)) + ret0 := and(ret0, eq(mulmod(y, y, q), addmod(mulmod(x, mulmod(x, x, q), q), 3, q))) + mstore(hash_mptr, x) + mstore(add(hash_mptr, 0x20), y) + ret1 := add(proof_cptr, 0x40) + ret2 := add(hash_mptr, 0x40) + } + + // Squeeze challenge by keccak256(memory[0..hash_mptr]), + // and store hash mod r as challenge in challenge_mptr, + // and push back hash in 0x00 as the first input for next squeeze. + // Return updated (challenge_mptr, hash_mptr). + function squeeze_challenge(challenge_mptr, hash_mptr, r) -> ret0, ret1 { + let hash := keccak256(0x00, hash_mptr) + mstore(challenge_mptr, mod(hash, r)) + mstore(0x00, hash) + ret0 := add(challenge_mptr, 0x20) + ret1 := 0x20 + } + + // Squeeze challenge without absorbing new input from calldata, + // by putting an extra 0x01 in memory[0x20] and squeeze by keccak256(memory[0..21]), + // and store hash mod r as challenge in challenge_mptr, + // and push back hash in 0x00 as the first input for next squeeze. + // Return updated (challenge_mptr). + function squeeze_challenge_cont(challenge_mptr, r) -> ret { + mstore8(0x20, 0x01) + let hash := keccak256(0x00, 0x21) + mstore(challenge_mptr, mod(hash, r)) + mstore(0x00, hash) + ret := add(challenge_mptr, 0x20) + } + + // Batch invert values in memory[mptr_start..mptr_end] in place. + // Return updated (success). + function batch_invert(success, mptr_start, mptr_end, r) -> ret { + let gp_mptr := mptr_end + let gp := mload(mptr_start) + let mptr := add(mptr_start, 0x20) + for + {} + lt(mptr, sub(mptr_end, 0x20)) + {} + { + gp := mulmod(gp, mload(mptr), r) + mstore(gp_mptr, gp) + mptr := add(mptr, 0x20) + gp_mptr := add(gp_mptr, 0x20) + } + gp := mulmod(gp, mload(mptr), r) + + mstore(gp_mptr, 0x20) + mstore(add(gp_mptr, 0x20), 0x20) + mstore(add(gp_mptr, 0x40), 0x20) + mstore(add(gp_mptr, 0x60), gp) + mstore(add(gp_mptr, 0x80), sub(r, 2)) + mstore(add(gp_mptr, 0xa0), r) + ret := and(success, staticcall(gas(), 0x05, gp_mptr, 0xc0, gp_mptr, 0x20)) + let all_inv := mload(gp_mptr) + + let first_mptr := mptr_start + let second_mptr := add(first_mptr, 0x20) + gp_mptr := sub(gp_mptr, 0x20) + for + {} + lt(second_mptr, mptr) + {} + { + let inv := mulmod(all_inv, mload(gp_mptr), r) + all_inv := mulmod(all_inv, mload(mptr), r) + mstore(mptr, inv) + mptr := sub(mptr, 0x20) + gp_mptr := sub(gp_mptr, 0x20) + } + let inv_first := mulmod(all_inv, mload(second_mptr), r) + let inv_second := mulmod(all_inv, mload(first_mptr), r) + mstore(first_mptr, inv_first) + mstore(second_mptr, inv_second) + } + + // Add (x, y) into point at (0x00, 0x20). + // Return updated (success). + function ec_add_acc(success, x, y) -> ret { + mstore(0x40, x) + mstore(0x60, y) + ret := and(success, staticcall(gas(), 0x06, 0x00, 0x80, 0x00, 0x40)) + } + + // Scale point at (0x00, 0x20) by scalar. + function ec_mul_acc(success, scalar) -> ret { + mstore(0x40, scalar) + ret := and(success, staticcall(gas(), 0x07, 0x00, 0x60, 0x00, 0x40)) + } + + // Add (x, y) into point at (0x80, 0xa0). + // Return updated (success). + function ec_add_tmp(success, x, y) -> ret { + mstore(0xc0, x) + mstore(0xe0, y) + ret := and(success, staticcall(gas(), 0x06, 0x80, 0x80, 0x80, 0x40)) + } + + // Scale point at (0x80, 0xa0) by scalar. + // Return updated (success). + function ec_mul_tmp(success, scalar) -> ret { + mstore(0xc0, scalar) + ret := and(success, staticcall(gas(), 0x07, 0x80, 0x60, 0x80, 0x40)) + } + + // Perform pairing check. + // Return updated (success). + function ec_pairing(success, lhs_x, lhs_y, rhs_x, rhs_y) -> ret { + mstore(0x00, lhs_x) + mstore(0x20, lhs_y) + mstore(0x40, mload(G2_X_1_MPTR)) + mstore(0x60, mload(G2_X_2_MPTR)) + mstore(0x80, mload(G2_Y_1_MPTR)) + mstore(0xa0, mload(G2_Y_2_MPTR)) + mstore(0xc0, rhs_x) + mstore(0xe0, rhs_y) + mstore(0x100, mload(NEG_S_G2_X_1_MPTR)) + mstore(0x120, mload(NEG_S_G2_X_2_MPTR)) + mstore(0x140, mload(NEG_S_G2_Y_1_MPTR)) + mstore(0x160, mload(NEG_S_G2_Y_2_MPTR)) + ret := and(success, staticcall(gas(), 0x08, 0x00, 0x180, 0x00, 0x20)) + ret := and(ret, mload(0x00)) + } + + // Modulus + let q := 21888242871839275222246405745257275088696311157297823662689037894645226208583 // BN254 base field + let r := 21888242871839275222246405745257275088548364400416034343698204186575808495617 // BN254 scalar field + + // Initialize success as true + let success := true + + { + {%- match self.embedded_vk %} + {%- when Some with (embedded_vk) %} + // Load vk_digest and num_instances of vk into memory + {%- for (name, chunk) in embedded_vk.constants[..2] %} + mstore({{ vk_mptr + loop.index0 }}, {{ chunk|hex_padded(64) }}) // {{ name }} + {%- endfor %} + {%- when None %} + // Copy vk_digest and num_instances of vk into memory + extcodecopy(vk, VK_MPTR, 0x00, 0x40) + {%- endmatch %} + + // Check valid length of proof + success := and(success, eq({{ proof_len|hex() }}, calldataload(PROOF_LEN_CPTR))) + + // Check valid length of instances + let num_instances := mload(NUM_INSTANCES_MPTR) + success := and(success, eq(num_instances, calldataload(NUM_INSTANCE_CPTR))) + + // Absorb vk diegst + mstore(0x00, mload(VK_DIGEST_MPTR)) + + // Read instances and witness commitments and generate challenges + let hash_mptr := 0x20 + let instance_cptr := INSTANCE_CPTR + for + { let instance_cptr_end := add(instance_cptr, mul(0x20, num_instances)) } + lt(instance_cptr, instance_cptr_end) + {} + { + let instance := calldataload(instance_cptr) + success := and(success, lt(instance, r)) + mstore(hash_mptr, instance) + instance_cptr := add(instance_cptr, 0x20) + hash_mptr := add(hash_mptr, 0x20) + } + + let proof_cptr := PROOF_CPTR + let challenge_mptr := CHALLENGE_MPTR + {%- for num_advices in num_advices %} + + // Phase {{ loop.index }} + for + { let proof_cptr_end := add(proof_cptr, {{ (2 * 32 * num_advices)|hex() }}) } + lt(proof_cptr, proof_cptr_end) + {} + { + success, proof_cptr, hash_mptr := read_ec_point(success, proof_cptr, hash_mptr, q) + } + + challenge_mptr, hash_mptr := squeeze_challenge(challenge_mptr, hash_mptr, r) + {%- for _ in 0..num_challenges[loop.index0] - 1 %} + challenge_mptr := squeeze_challenge_cont(challenge_mptr, r) + {%- endfor %} + {%- endfor %} + + // Read evaluations + for + { let proof_cptr_end := add(proof_cptr, {{ (32 * num_evals)|hex() }}) } + lt(proof_cptr, proof_cptr_end) + {} + { + let eval := calldataload(proof_cptr) + success := and(success, lt(eval, r)) + mstore(hash_mptr, eval) + proof_cptr := add(proof_cptr, 0x20) + hash_mptr := add(hash_mptr, 0x20) + } + + // Read batch opening proof and generate challenges + {%- match scheme %} + {%- when Bdfg21 %} + challenge_mptr, hash_mptr := squeeze_challenge(challenge_mptr, hash_mptr, r) // zeta + challenge_mptr := squeeze_challenge_cont(challenge_mptr, r) // nu + + success, proof_cptr, hash_mptr := read_ec_point(success, proof_cptr, hash_mptr, q) // W + + challenge_mptr, hash_mptr := squeeze_challenge(challenge_mptr, hash_mptr, r) // mu + + success, proof_cptr, hash_mptr := read_ec_point(success, proof_cptr, hash_mptr, q) // W' + {%- when Gwc19 %} + challenge_mptr, hash_mptr := squeeze_challenge(challenge_mptr, hash_mptr, r) // nu + + for + { let proof_cptr_end := add(proof_cptr, {{ (2 * 32 * num_rotations)|hex() }}) } + lt(proof_cptr, proof_cptr_end) + {} + { + success, proof_cptr, hash_mptr := read_ec_point(success, proof_cptr, hash_mptr, q) + } + + challenge_mptr, hash_mptr := squeeze_challenge(challenge_mptr, hash_mptr, r) // mu + {%- endmatch %} + + {%~ match self.embedded_vk %} + {%- when Some with (embedded_vk) %} + // Load full vk into memory + {%- for (name, chunk) in embedded_vk.constants %} + mstore({{ vk_mptr + loop.index0 }}, {{ chunk|hex_padded(64) }}) // {{ name }} + {%- endfor %} + {%- for (x, y) in embedded_vk.fixed_comms %} + {%- let offset = embedded_vk.constants.len() %} + mstore({{ vk_mptr + offset + 2 * loop.index0 }}, {{ x|hex_padded(64) }}) // fixed_comms[{{ loop.index0 }}].x + mstore({{ vk_mptr + offset + 2 * loop.index0 + 1 }}, {{ y|hex_padded(64) }}) // fixed_comms[{{ loop.index0 }}].y + {%- endfor %} + {%- for (x, y) in embedded_vk.permutation_comms %} + {%- let offset = embedded_vk.constants.len() + 2 * embedded_vk.fixed_comms.len() %} + mstore({{ vk_mptr + offset + 2 * loop.index0 }}, {{ x|hex_padded(64) }}) // permutation_comms[{{ loop.index0 }}].x + mstore({{ vk_mptr + offset + 2 * loop.index0 + 1 }}, {{ y|hex_padded(64) }}) // permutation_comms[{{ loop.index0 }}].y + {%- endfor %} + {%- when None %} + // Copy full vk into memory + extcodecopy(vk, VK_MPTR, 0x00, {{ vk_len|hex() }}) + {%- endmatch %} + + // Read accumulator from instances + if mload(HAS_ACCUMULATOR_MPTR) { + let num_limbs := mload(NUM_ACC_LIMBS_MPTR) + let num_limb_bits := mload(NUM_ACC_LIMB_BITS_MPTR) + + let cptr := add(INSTANCE_CPTR, mul(mload(ACC_OFFSET_MPTR), 0x20)) + let lhs_y_off := mul(num_limbs, 0x20) + let rhs_x_off := mul(lhs_y_off, 2) + let rhs_y_off := mul(lhs_y_off, 3) + let lhs_x := calldataload(cptr) + let lhs_y := calldataload(add(cptr, lhs_y_off)) + let rhs_x := calldataload(add(cptr, rhs_x_off)) + let rhs_y := calldataload(add(cptr, rhs_y_off)) + for + { + let cptr_end := add(cptr, mul(0x20, num_limbs)) + let shift := num_limb_bits + } + lt(cptr, cptr_end) + {} + { + cptr := add(cptr, 0x20) + lhs_x := add(lhs_x, shl(shift, calldataload(cptr))) + lhs_y := add(lhs_y, shl(shift, calldataload(add(cptr, lhs_y_off)))) + rhs_x := add(rhs_x, shl(shift, calldataload(add(cptr, rhs_x_off)))) + rhs_y := add(rhs_y, shl(shift, calldataload(add(cptr, rhs_y_off)))) + shift := add(shift, num_limb_bits) + } + + success := and(success, and(lt(lhs_x, q), lt(lhs_y, q))) + success := and(success, eq(mulmod(lhs_y, lhs_y, q), addmod(mulmod(lhs_x, mulmod(lhs_x, lhs_x, q), q), 3, q))) + success := and(success, and(lt(rhs_x, q), lt(rhs_y, q))) + success := and(success, eq(mulmod(rhs_y, rhs_y, q), addmod(mulmod(rhs_x, mulmod(rhs_x, rhs_x, q), q), 3, q))) + + mstore(ACC_LHS_X_MPTR, lhs_x) + mstore(ACC_LHS_Y_MPTR, lhs_y) + mstore(ACC_RHS_X_MPTR, rhs_x) + mstore(ACC_RHS_Y_MPTR, rhs_y) + } + + pop(q) + } + + // Return 0 early if anything from calldata is invalid + if iszero(success) { + mstore(0x00, 0) + return(0x00, 0x20) + } + + // Compute lagrange evaluations and instance evaluation + { + let k := mload(K_MPTR) + let x := mload(X_MPTR) + let x_n := x + for + { let idx := 0 } + lt(idx, k) + { idx := add(idx, 1) } + { + x_n := mulmod(x_n, x_n, r) + } + + let omega := mload(OMEGA_MPTR) + + let mptr := X_N_MPTR + let mptr_end := add(mptr, mul(0x20, add(mload(NUM_INSTANCES_MPTR), {{ num_neg_lagranges }}))) + if iszero(mload(NUM_INSTANCES_MPTR)) { + mptr_end := add(mptr_end, 0x20) + } + for + { let pow_of_omega := mload(OMEGA_INV_TO_L_MPTR) } + lt(mptr, mptr_end) + { mptr := add(mptr, 0x20) } + { + mstore(mptr, addmod(x, sub(r, pow_of_omega), r)) + pow_of_omega := mulmod(pow_of_omega, omega, r) + } + let x_n_minus_1 := addmod(x_n, sub(r, 1), r) + mstore(mptr_end, x_n_minus_1) + success := batch_invert(success, X_N_MPTR, add(mptr_end, 0x20), r) + + mptr := X_N_MPTR + let l_i_common := mulmod(x_n_minus_1, mload(N_INV_MPTR), r) + for + { let pow_of_omega := mload(OMEGA_INV_TO_L_MPTR) } + lt(mptr, mptr_end) + { mptr := add(mptr, 0x20) } + { + mstore(mptr, mulmod(l_i_common, mulmod(mload(mptr), pow_of_omega, r), r)) + pow_of_omega := mulmod(pow_of_omega, omega, r) + } + + let l_blind := mload(add(X_N_MPTR, 0x20)) + let l_i_cptr := add(X_N_MPTR, 0x40) + for + { let l_i_cptr_end := add(X_N_MPTR, {{ (num_neg_lagranges * 32)|hex() }}) } + lt(l_i_cptr, l_i_cptr_end) + { l_i_cptr := add(l_i_cptr, 0x20) } + { + l_blind := addmod(l_blind, mload(l_i_cptr), r) + } + + let instance_eval := 0 + for + { + let instance_cptr := INSTANCE_CPTR + let instance_cptr_end := add(instance_cptr, mul(0x20, mload(NUM_INSTANCES_MPTR))) + } + lt(instance_cptr, instance_cptr_end) + { + instance_cptr := add(instance_cptr, 0x20) + l_i_cptr := add(l_i_cptr, 0x20) + } + { + instance_eval := addmod(instance_eval, mulmod(mload(l_i_cptr), calldataload(instance_cptr), r), r) + } + + let x_n_minus_1_inv := mload(mptr_end) + let l_last := mload(X_N_MPTR) + let l_0 := mload(add(X_N_MPTR, {{ (num_neg_lagranges * 32)|hex() }})) + + mstore(X_N_MPTR, x_n) + mstore(X_N_MINUS_1_INV_MPTR, x_n_minus_1_inv) + mstore(L_LAST_MPTR, l_last) + mstore(L_BLIND_MPTR, l_blind) + mstore(L_0_MPTR, l_0) + mstore(INSTANCE_EVAL_MPTR, instance_eval) + } + + // Compute quotient evavluation + { + let quotient_eval_numer + let delta := 4131629893567559867359510883348571134090853742863529169391034518566172092834 + let y := mload(Y_MPTR) + + {%- for code_block in quotient_eval_numer_computations %} + { + {%- for line in code_block %} + {{ line }} + {%- endfor %} + } + {%- endfor %} + + pop(y) + pop(delta) + + let quotient_eval := mulmod(quotient_eval_numer, mload(X_N_MINUS_1_INV_MPTR), r) + mstore(QUOTIENT_EVAL_MPTR, quotient_eval) + } + + // Compute quotient commitment + { + mstore(0x00, calldataload(LAST_QUOTIENT_X_CPTR)) + mstore(0x20, calldataload(add(LAST_QUOTIENT_X_CPTR, 0x20))) + let x_n := mload(X_N_MPTR) + for + { + let cptr := sub(LAST_QUOTIENT_X_CPTR, 0x40) + let cptr_end := sub(FIRST_QUOTIENT_X_CPTR, 0x40) + } + lt(cptr_end, cptr) + {} + { + success := ec_mul_acc(success, x_n) + success := ec_add_acc(success, calldataload(cptr), calldataload(add(cptr, 0x20))) + cptr := sub(cptr, 0x40) + } + mstore(QUOTIENT_X_MPTR, mload(0x00)) + mstore(QUOTIENT_Y_MPTR, mload(0x20)) + } + + // Compute pairing lhs and rhs + { + {%- for code_block in pcs_computations %} + { + {%- for line in code_block %} + {{ line }} + {%- endfor %} + } + {%- endfor %} + } + + // Random linear combine with accumulator + if mload(HAS_ACCUMULATOR_MPTR) { + mstore(0x00, mload(ACC_LHS_X_MPTR)) + mstore(0x20, mload(ACC_LHS_Y_MPTR)) + mstore(0x40, mload(ACC_RHS_X_MPTR)) + mstore(0x60, mload(ACC_RHS_Y_MPTR)) + mstore(0x80, mload(PAIRING_LHS_X_MPTR)) + mstore(0xa0, mload(PAIRING_LHS_Y_MPTR)) + mstore(0xc0, mload(PAIRING_RHS_X_MPTR)) + mstore(0xe0, mload(PAIRING_RHS_Y_MPTR)) + let challenge := mod(keccak256(0x00, 0x100), r) + + // [pairing_lhs] += challenge * [acc_lhs] + success := ec_mul_acc(success, challenge) + success := ec_add_acc(success, mload(PAIRING_LHS_X_MPTR), mload(PAIRING_LHS_Y_MPTR)) + mstore(PAIRING_LHS_X_MPTR, mload(0x00)) + mstore(PAIRING_LHS_Y_MPTR, mload(0x20)) + + // [pairing_rhs] += challenge * [acc_rhs] + mstore(0x00, mload(ACC_RHS_X_MPTR)) + mstore(0x20, mload(ACC_RHS_Y_MPTR)) + success := ec_mul_acc(success, challenge) + success := ec_add_acc(success, mload(PAIRING_RHS_X_MPTR), mload(PAIRING_RHS_Y_MPTR)) + mstore(PAIRING_RHS_X_MPTR, mload(0x00)) + mstore(PAIRING_RHS_Y_MPTR, mload(0x20)) + } + + // Perform pairing + success := ec_pairing( + success, + mload(PAIRING_LHS_X_MPTR), + mload(PAIRING_LHS_Y_MPTR), + mload(PAIRING_RHS_X_MPTR), + mload(PAIRING_RHS_Y_MPTR) + ) + + // Return 0 if anything fails + if iszero(success) { + mstore(0x00, 0) + return(0x00, 0x20) + } + + // Return 1 as result if everything succeeds + mstore(0x00, 1) + return(0x00, 0x20) + } + } +} diff --git a/crates/halo2-verifier/templates/Halo2VerifyingKey.sol b/crates/halo2-verifier/templates/Halo2VerifyingKey.sol new file mode 100644 index 00000000..6469916d --- /dev/null +++ b/crates/halo2-verifier/templates/Halo2VerifyingKey.sol @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.26; + +contract Halo2VerifyingKey { + constructor() { + assembly { + {%- for (name, chunk) in constants %} + mstore({{ (32 * loop.index0)|hex_padded(4) }}, {{ chunk|hex_padded(64) }}) // {{ name }} + {%- endfor %} + {%- for (x, y) in fixed_comms %} + {%- let offset = constants.len() %} + mstore({{ (32 * (offset + 2 * loop.index0))|hex_padded(4) }}, {{ x|hex_padded(64) }}) // fixed_comms[{{ loop.index0 }}].x + mstore({{ (32 * (offset + 2 * loop.index0 + 1))|hex_padded(4) }}, {{ y|hex_padded(64) }}) // fixed_comms[{{ loop.index0 }}].y + {%- endfor %} + {%- for (x, y) in permutation_comms %} + {%- let offset = constants.len() + 2 * fixed_comms.len() %} + mstore({{ (32 * (offset + 2 * loop.index0))|hex_padded(4) }}, {{ x|hex_padded(64) }}) // permutation_comms[{{ loop.index0 }}].x + mstore({{ (32 * (offset + 2 * loop.index0 + 1))|hex_padded(4) }}, {{ y|hex_padded(64) }}) // permutation_comms[{{ loop.index0 }}].y + {%- endfor %} + + return(0, {{ (32 * (constants.len() + 2 * fixed_comms.len() + 2 * permutation_comms.len()))|hex() }}) + } + } +} diff --git a/crates/integration-tests/Cargo.toml b/crates/integration-tests/Cargo.toml new file mode 100644 index 00000000..166ddf36 --- /dev/null +++ b/crates/integration-tests/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "integration-tests" +version = "0.1.0" +edition.workspace = true +authors.workspace = true +homepage.workspace = true +license.workspace = true +categories.workspace = true +repository.workspace = true + +[dependencies] +alloy-contract = { workspace = true } +alloy-primitives = { workspace = true } +alloy-sol-types = { workspace = true, features = ["json"] } +evm-utils = { workspace = true } +halo2_proofs = { workspace = true } +halo2_solidity_verifier = { workspace = true } +hex = { workspace = true } +rand = { workspace = true, features = ["small_rng"] } +rstest = { workspace = true } +serde = { workspace = true } +serde_json = { workspace = true } +shielder-circuits = { workspace = true } +shielder-rust-sdk = { workspace = true, features = ["account", "contract", "conversion", "parameter_generation", "powers_of_tau", "permit2"] } diff --git a/crates/integration-tests/src/lib.rs b/crates/integration-tests/src/lib.rs new file mode 100644 index 00000000..5096d00a --- /dev/null +++ b/crates/integration-tests/src/lib.rs @@ -0,0 +1,32 @@ +#![cfg(test)] +#![feature(assert_matches)] + +use std::{fs::File, io::Read}; + +use alloy_primitives::Address; +use evm_utils::{compilation::source_to_bytecode, EvmRunner}; + +mod permit2; +mod poseidon2; +mod proving_utils; +mod shielder; +mod token; +mod verifier; + +const CONTRACTS_DIR: &str = "../../contracts"; + +fn read_contract(contract_name: &str) -> String { + let mut contents = String::new(); + let mut file = File::open(format!("{CONTRACTS_DIR}/{contract_name}")) + .expect("Cannot open contract source file"); + file.read_to_string(&mut contents) + .expect("Cannot read contract source file"); + contents +} + +fn deploy_contract(contract_filename: &str, contract_name: &str, evm: &mut EvmRunner) -> Address { + let solidity_code = read_contract(contract_filename); + let compiled_bytecode = source_to_bytecode(solidity_code, contract_name, true); + evm.create(compiled_bytecode, None) + .unwrap_or_else(|_| panic!("Failed to deploy {contract_name} contract")) +} diff --git a/crates/integration-tests/src/permit2.rs b/crates/integration-tests/src/permit2.rs new file mode 100644 index 00000000..3eedb04e --- /dev/null +++ b/crates/integration-tests/src/permit2.rs @@ -0,0 +1,26 @@ +use alloy_sol_types::{sol, SolCall}; +use shielder_rust_sdk::permit2::{get_eip712_hash, sign_message, PermitTransferFrom}; + +// @dev compile the SC suite with forge and: +// cat artifacts/Permit2.sol/Permit2.json | jq .bytecode.object +pub const PERMIT2_BYTECODE: &str = "60c0346100bb574660a052602081017f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a86681527f9ac997416e8ff9d2ff6bebeb7149f65cdae5e32e2b90440b566bb3044041d36a60408301524660608301523060808301526080825260a082019180831060018060401b038411176100a55782604052519020608052611b5990816100c18239608051816114c4015260a0518161149e0152f35b634e487b7160e01b600052604160045260246000fd5b600080fdfe6040608081526004908136101561001557600080fd5b600090813560e01c80630d58b1db14610e9f578063137c29fe14610d1c5780632a2d80d114610abd5780632b67b5701461094757806330f28b7a146108845780633644e5151461086157806336c78516146108175780633ff9dcb1146107b55780634fe02b441461077657806365d9723c1461066657806387517c4514610584578063927da105146104f8578063cc53287f14610417578063edd9444b146102eb5763fe8ec1a7146100c657600080fd5b346102e75760c03660031901126102e7576001600160401b0383358181116102e3576100f59036908601611185565b6024358281116102df5761010c9036908701611155565b610114611069565b916084358581116102db5761012c9036908a016110fe565b98909560a4359081116102d757610145913691016110fe565b96909581519061015482610fcb565b606b82527f5065726d697442617463685769746e6573735472616e7366657246726f6d285460208301527f6f6b656e5065726d697373696f6e735b5d207065726d69747465642c61646472838301527f657373207370656e6465722c75696e74323536206e6f6e63652c75696e74323560608301526a0d88191958591b1a5b994b60aa1b608083015282519a8b91816101f16020850180966117e7565b918237018a8152039961020c601f199b8c8101835282611001565b5190209085515161021c81611763565b908a5b8181106102aa5750506102a7999a61029e918351610251816102456020820180956117ba565b03848101835282611001565b519020602089810151858b015195519182019687526040820192909252336060820152608081019190915260a081019390935260643560c08401528260e081015b03908101835282611001565b5190209361161a565b80f35b806102c26102bc6102d2938c5161127e565b51611899565b6102cc828661127e565b52611795565b61021f565b8880fd5b8780fd5b8480fd5b8380fd5b5080fd5b5091346102e75760803660031901126102e7576001600160401b039080358281116102e35761031d9036908301611185565b6024358381116102df576103349036908401611155565b93909261033f611069565b9160643590811161041357610356913691016110fe565b9490938351519761036689611763565b98885b8181106103f15750506102a7979881516103998161038b6020820180956117ba565b03601f198101835282611001565b5190206020860151828701519083519260208401947ffcf35f5ac6a2c28868dc44c302166470266239195f02b0ee408334829333b7668652840152336060840152608083015260a082015260a0815261029e81610fe6565b808b6102cc826104086102bc61040e968d5161127e565b9261127e565b610369565b8680fd5b5082346104f457602090816003193601126102e3578035906001600160401b0382116102df5761044991369101611155565b929091845b848110610459578580f35b8061046f61046a600193888861136c565b61137c565b6104848461047e848a8a61136c565b0161137c565b33895283855285892091848060a01b0380911692838b528652868a20911690818a5285528589206bffffffffffffffffffffffff60a01b81541690558551918252848201527f89b1add15eff56b3dfe299ad94e01f2b52fbcb80ae1a3baea6ae8c04cb2b98a4853392a20161044e565b8280fd5b50346102e75760603660031901126102e7576105808161051661103d565b9361051f611053565b610527611069565b6001600160a01b03968716835260016020908152848420928816845291825283832090871683528152919020549251938316845260a083901c65ffffffffffff169084015260d09190911c604083015281906060820190565b0390f35b50346102e75760803660031901126102e75761059e61103d565b906105a7611053565b916105b0611069565b906064359265ffffffffffff93848116908181036102db577fda9fa7c1b00402c17d0161b249b1ab8bbec047c5a52207b9c112deffd817036b9333895260016020528389209660018060a01b0380921697888b5260205281858b20991698898b52602052848a2092841560001461065e57504216905b82546001600160d01b03191660a09290921b65ffffffffffff60a01b169190911795169485179055815193845260208401523392a480f35b905090610626565b5082346104f45760603660031901126104f45761068161103d565b9061068a611053565b9265ffffffffffff60443581811693908481036102db57338852602091600183528489209660018060a01b0380911697888b528452858a20981697888a5283528489205460d01c93848711156107675761ffff90858403161161075957503380895260018352848920878a528352848920888a52835284892080546001600160d01b031660d09390931b6001600160d01b03191692909217909155835194855290840191909152917f55eb90d810e1700b35a8e7e25395ff7f2b2259abd7415ca2284dfb1c246418f39190a480f35b8451631269ad1360e11b8152fd5b508451633ab3447f60e11b8152fd5b50346102e757806003193601126102e75760209181906001600160a01b0361079c61103d565b1681528084528181206024358252845220549051908152f35b5082346104f457816003193601126104f4577f3704902f963766a4e561bbaab6e6cdc1b1dd12f6e9e99648da8843b3f46b918d90359160243533855284602052818520848652602052818520818154179055815193845260208401523392a280f35b823461085e57608036600319011261085e5761083161103d565b610839611053565b610841611069565b606435916001600160a01b03831683036102df576102a7936112a8565b80fd5b50346102e757816003193601126102e75760209061087d61149b565b9051908152f35b508290346104f4576101003660031901126104f4576108a236611093565b90806083193601126102e3576108b6611022565b9160e4356001600160401b038111610943576102a7946108d8913691016110fe565b9390926108e58351611899565b6020840151828501519083519260208401947f939c21a48a8dbe3a9a2404a1d46691e4d39f6583d6ec6b35714604c986d801068652840152336060840152608083015260a082015260a0815261093a81610fe6565b51902091611587565b8580fd5b5091346102e7576101003660031901126102e75761096361103d565b366023190160c081126102e357608085519161097e83610fb0565b126102e35784519061098f82610f7f565b6001600160a01b03916024358381168103610413578152604435838116810361041357602082015265ffffffffffff60643581811681036102db57888301526084359081168103610413576060820152815260a435938285168503610943576020820194855260c4359087830182815260e4356001600160401b0381116102d757610a1d90369084016110fe565b929093804211610aa7575050918591610a976102a7999a610a9d95610a428851611812565b90898c511690519083519260208401947ff3841cd1ff0085026a6327b620b67997ce40f282c88a8e905a7a5626e310f3d086528401526060830152608082015260808152610a8f81610fcb565b519020611556565b916118fe565b5192511691611390565b8a5163cd21db4f60e01b81529182015260249150fd5b5091346102e75760606003199381853601126102e357610adb61103d565b926024908135926001600160401b03978885116102db57859085360301126104135780519785890189811082821117610d0a578252848301358181116102d757850190366023830112156102d7578382013591610b378361112b565b90610b4485519283611001565b838252602093878584019160071b83010191368311610d06578801905b828210610ca9575050508a526044610b7a86880161107f565b96838c01978852013594838b0191868352604435908111610ca557610ba290369087016110fe565b959096804211610c93575050508998995151610bbd81611763565b908b5b818110610c7057505092889492610a9792610c3d97958351610be98161038b86820180956117ba565b5190209060018060a01b039a8b8b51169151928551948501957faf1b0d30d2cab0380e68f0689007e3254993c596f2fdd0aaa7f4d04f794408638752850152830152608082015260808152610a8f81610fcb565b51169082515192845b848110610c51578580f35b80610c6a8585610c64600195875161127e565b51611390565b01610c46565b806102c2610c858e9f9e93610c8b945161127e565b51611812565b9b9a9b610bc0565b855163cd21db4f60e01b815291820152fd5b8a80fd5b608082360312610d0657856080918851610cc281610f7f565b610ccb8561107f565b8152610cd883860161107f565b83820152610ce78a8601611142565b8a8201528d610cf7818701611142565b90820152815201910190610b61565b8c80fd5b634e487b7160e01b8952604184528489fd5b5082346104f4576101403660031901126104f457610d3936611093565b91806083193601126102e357610d4d611022565b6001600160401b0393906101043585811161041357610d6f90369086016110fe565b9093610124359687116102db57610d8f61093a966102a7983691016110fe565b969095825190610d9e82610fcb565b606482527f5065726d69745769746e6573735472616e7366657246726f6d28546f6b656e5060208301527f65726d697373696f6e73207065726d69747465642c6164647265737320737065848301527f6e6465722c75696e74323536206e6f6e63652c75696e7432353620646561646c6060830152631a5b994b60e21b6080830152835194859181610e346020850180966117e7565b918237018b81520393610e4f601f1995868101835282611001565b51902092610e5d8651611899565b6020878101518589015195519182019687526040820192909252336060820152608081019190915260a081019390935260e43560c08401528260e08101610292565b5082346104f4576020806003193601126102e35781356001600160401b03928382116109435736602383011215610943578101359283116102df576024906007368386831b8401011161041357865b858110610ef9578780f35b80821b830190608060231983360301126102d757610f79888760019460608351610f2281610f7f565b610f5e6084610f328d860161107f565b94858452610f426044820161107f565b8097850152610f536064820161107f565b80988501520161107f565b9182910152868060a01b0380808093169516931691166112a8565b01610eee565b608081019081106001600160401b03821117610f9a57604052565b634e487b7160e01b600052604160045260246000fd5b606081019081106001600160401b03821117610f9a57604052565b60a081019081106001600160401b03821117610f9a57604052565b60c081019081106001600160401b03821117610f9a57604052565b90601f801991011681019081106001600160401b03821117610f9a57604052565b60c435906001600160a01b038216820361103857565b600080fd5b600435906001600160a01b038216820361103857565b602435906001600160a01b038216820361103857565b604435906001600160a01b038216820361103857565b35906001600160a01b038216820361103857565b6003190190608082126110385760408051906110ae82610fb0565b808294126110385780518181018181106001600160401b03821117610f9a5782526004356001600160a01b0381168103611038578152602435602082015282526044356020830152606435910152565b9181601f84011215611038578235916001600160401b038311611038576020838186019501011161103857565b6001600160401b038111610f9a5760051b60200190565b359065ffffffffffff8216820361103857565b9181601f84011215611038578235916001600160401b038311611038576020808501948460061b01011161103857565b9190916060818403126110385760408051916111a083610fb0565b829481356001600160401b039081811161103857830182601f820112156110385780356111cc8161112b565b926111d987519485611001565b818452602094858086019360061b85010193818511611038579086899897969594939201925b84841061121c575050505050855280820135908501520135910152565b909192939495969784830312611038578851908982019082821085831117611269578a928992845261124d8761107f565b81528287013583820152815201930191908897969594936111ff565b60246000634e487b7160e01b81526041600452fd5b80518210156112925760209160051b010190565b634e487b7160e01b600052603260045260246000fd5b92919260018060a01b03604060008284168152600160205282828220961695868252602052818120338252602052209485549565ffffffffffff8760a01c1680421161135457508287169683880361130b575b505061130995501692611ad0565b565b87848416116000146113305760405163f96fb07160e01b815260048101899052602490fd5b8383611309990316906bffffffffffffffffffffffff60a01b1617905538806112fb565b60249060405190636c0d979760e11b82526004820152fd5b91908110156112925760061b0190565b356001600160a01b03811681036110385790565b9065ffffffffffff908160608401511660018060a01b03908185511694826020820151169280866040809401511695169560009187835260016020528383208984526020528383209916988983526020528282209184835460d01c0361148a57918561147e94927fc6a377bfc4eb120024a8ac08eef205be16b817020812c73223e81d1bdb9708ec989796945087156000146114835742165b6001850160d01b6001600160d01b03191660a09190911b65ffffffffffff60a01b1617179055516001600160a01b03909316835265ffffffffffff938416602084015290921660408201529081906060820190565b0390a4565b5086611429565b8351633ab3447f60e11b8152600490fd5b467f0000000000000000000000000000000000000000000000000000000000000000036114e6577f000000000000000000000000000000000000000000000000000000000000000090565b60405160208101907f8cad95687ba82c2ce50e74f7b754645e5117c3a5bec8151c0726d5857980a86682527f9ac997416e8ff9d2ff6bebeb7149f65cdae5e32e2b90440b566bb3044041d36a60408201524660608201523060808201526080815261155081610fcb565b51902090565b61155e61149b565b9060405190602082019261190160f01b8452602283015260428201526042815261155081610f7f565b9192909360a43593604084015180421161160257506020845101518086116115ea5750918591610a976115c7946115c2602088015186611715565b611556565b51516001600160a01b039081169260843591821682036110385761130993611ad0565b60249060405190633728b83d60e01b82526004820152fd5b6024906040519063cd21db4f60e01b82526004820152fd5b9590939580515195604092838301518042116116fe57508488036116ea57611651918691610a9760209b6115c28d88015186611715565b60005b868110611665575050505050505050565b61167081835161127e565b518861167d83878a61136c565b013590898101518083116116d35750918188888860019685966116a7575b50505050505001611654565b6116c8956116c29261046a928a8060a01b039051169561136c565b91611ad0565b80388888888361169b565b602490865190633728b83d60e01b82526004820152fd5b83516001621398b960e31b03198152600490fd5b60249085519063cd21db4f60e01b82526004820152fd5b90600160ff82161b9160018060a01b0316600052600060205260406000209060081c600052602052604060002081815418809155161561175157565b604051633ab3447f60e11b8152600490fd5b9061176d8261112b565b61177a6040519182611001565b828152809261178b601f199161112b565b0190602036910137565b60001981146117a45760010190565b634e487b7160e01b600052601160045260246000fd5b805160208092019160005b8281106117d3575050505090565b8351855293810193928101926001016117c5565b9081519160005b8381106117ff575050016000815290565b80602080928401015181850152016117ee565b60405160208101917f65626cad6cb96493bf6f5ebea28756c966f023ab9e8a83a7101849d5573b3678835260018060a01b038082511660408401526020820151166060830152606065ffffffffffff9182604082015116608085015201511660a082015260a0815260c081018181106001600160401b03821117610f9a5760405251902090565b6040516020808201927f618358ac3db8dc274f0cd8829da7e234bd48cd73c4a740aede1adec9846d06a1845260018060a01b038151166040840152015160608201526060815261155081610f7f565b9190826040910312611038576020823592013590565b6000843b6119f75750604182036119a75761191b828201826118e8565b939092604010156112925760209360009360ff6040608095013560f81c5b60405194855216868401526040830152606082015282805260015afa1561199b576000516001600160a01b0390811691821561198957160361197757565b604051632057875960e21b8152600490fd5b604051638baa579f60e01b8152600490fd5b6040513d6000823e3d90fd5b604082036119e5576119bb918101906118e8565b6001600160ff1b0381169260ff91821c601b019182116117a45760209360009360ff608094611939565b604051634be6321b60e01b8152600490fd5b918093946020926064604051809781958294630b135d3f60e11b9b8c8552600485015260406024850152816044850152848401378181018301889052601f01601f191681010301916001600160a01b03165afa918215611ac3578192611a7d575b50506001600160e01b03191603611a6b57565b604051632c19a72f60e21b8152600490fd5b9091506020813d8211611abb575b81611a9860209383611001565b810103126102e75751906001600160e01b03198216820361085e57503880611a58565b3d9150611a8b565b50604051903d90823e3d90fd5b9060006064926020958295604051946323b872dd60e01b86526004860152602485015260448401525af13d15601f3d1160016000511416171615611b1057565b60405162461bcd60e51b81526020600482015260146024820152731514905394d1915497d19493d357d1905253115160621b6044820152606490fdfea164736f6c6343000811000a"; + +sol! { + function DOMAIN_SEPARATOR() public view override returns (bytes32); +} + +pub fn domain_separator_calldata() -> Vec { + DOMAIN_SEPARATORCall {}.abi_encode() +} + +pub fn sign_permit( + permit: &PermitTransferFrom, + eip712_domain_separator: &[u8; 32], + private_key: &[u8; 32], +) -> Vec { + let message = get_eip712_hash(permit, eip712_domain_separator); + + let (r, s, v) = sign_message(&message, private_key); + + [r.to_vec(), s.to_vec(), vec![v]].concat() +} diff --git a/crates/integration-tests/src/poseidon2.rs b/crates/integration-tests/src/poseidon2.rs new file mode 100644 index 00000000..796d8ca5 --- /dev/null +++ b/crates/integration-tests/src/poseidon2.rs @@ -0,0 +1,43 @@ +use alloy_primitives::U256; +use alloy_sol_types::{sol, SolCall, SolValue}; +use evm_utils::{EvmRunner, SuccessResult}; +use halo2_proofs::halo2curves::bn256::Fr; +use shielder_circuits::utils::hash; +use shielder_rust_sdk::conversion::field_to_u256; + +use crate::deploy_contract; + +const POSEIDON2_CONTRACT_NAME: &str = "Poseidon2T8Assembly"; +const POSEIDON2_FILE_NAME: &str = "Poseidon2T8Assembly.sol"; + +sol! { + function hash(uint[7] memory) public pure returns (uint); +} + +fn encode_calldata(values: &[Fr; 7]) -> Vec { + let values = values + .iter() + .map(field_to_u256::) + .collect::>(); + let values = values.try_into().unwrap(); + hashCall { _0: values }.abi_encode() +} + +#[test] +fn verify_off_chain_and_on_chain_poseidon_preimage() { + let preimage = [1, 2, 3, 4, 5, 6, 7].map(Fr::from); + + let mut evm = EvmRunner::aleph_evm(); + let poseidon2_address = deploy_contract(POSEIDON2_FILE_NAME, POSEIDON2_CONTRACT_NAME, &mut evm); + + let calldata = encode_calldata(&preimage); + let response = match evm.call(poseidon2_address, calldata, None, None) { + Ok(SuccessResult { output, .. }) => output, + Err(why) => panic!("Failed to call Poseidon2 contract: {why}"), + }; + + let image_on_chain = ::abi_decode(&response, true).unwrap(); + let image_off_chain = hash(&preimage); + + assert_eq!(image_on_chain, field_to_u256(image_off_chain)); +} diff --git a/crates/integration-tests/src/proving_utils.rs b/crates/integration-tests/src/proving_utils.rs new file mode 100644 index 00000000..d5278631 --- /dev/null +++ b/crates/integration-tests/src/proving_utils.rs @@ -0,0 +1,77 @@ +use halo2_proofs::plonk::Circuit; +use rand::{RngCore, SeedableRng}; +use rstest::fixture; +use shielder_circuits::{ + circuits::{Params, ProvingKey, VerifyingKey}, + consts::RANGE_PROOF_CHUNK_SIZE, + deposit::DepositCircuit, + generate_keys_with_min_k, generate_proof, + new_account::NewAccountCircuit, + verify, + withdraw::WithdrawCircuit, + ProverKnowledge, F, MAX_K, +}; +use shielder_rust_sdk::{ + parameter_generation, + powers_of_tau::{get_ptau_file_path, read as read_setup_parameters, Format}, +}; + +/// Given circuit type `C`, construct a correct relation instance and generate a proof, accompanied +/// by the corresponding public input. +pub fn prepare_proof>() -> (Vec, Vec) { + let (params, pk, vk, mut rng) = setup::(); + + let prover_knowledge = PK::random_correct_example(&mut rng); + let circuit = prover_knowledge.create_circuit(); + let pub_input = prover_knowledge.serialize_public_input(); + + let proof = generate_proof(¶ms, &pk, circuit, &pub_input, &mut rng); + + // Canary check - should be already covered in other tests. + verify(¶ms, &vk, &proof, &pub_input).expect("Verification failed"); + + (proof, pub_input) +} + +/// Given circuit type `C`, generate params and a proving key. +pub fn prepare_proving_keys + Default>() -> (Params, ProvingKey) { + let (params, pk, _, _) = setup::(); + (params, pk) +} + +fn setup + Default>() -> (Params, ProvingKey, VerifyingKey, impl SeedableRng + RngCore) +{ + let full_params = read_setup_parameters( + get_ptau_file_path(MAX_K, Format::PerpetualPowersOfTau), + Format::PerpetualPowersOfTau, + ) + .expect("failed to read parameters from the ptau file"); + + let (params, _, pk, vk) = + generate_keys_with_min_k::(full_params).expect("Key generation failed"); + + (params, pk, vk, parameter_generation::rng()) +} + +pub type ProvingParams = (Params, ProvingKey); + +#[fixture] +#[once] +pub fn new_account_native_proving_params() -> ProvingParams { + println!("Preparing NewAccountNative proving keys"); + prepare_proving_keys::>() +} + +#[fixture] +#[once] +pub fn deposit_native_proving_params() -> ProvingParams { + println!("Preparing DepositNative proving keys"); + prepare_proving_keys::>() +} + +#[fixture] +#[once] +pub fn withdraw_native_proving_params() -> ProvingParams { + println!("Preparing WithdrawNative proving keys"); + prepare_proving_keys::>() +} diff --git a/crates/integration-tests/src/shielder/address_conversion.rs b/crates/integration-tests/src/shielder/address_conversion.rs new file mode 100644 index 00000000..78094345 --- /dev/null +++ b/crates/integration-tests/src/shielder/address_conversion.rs @@ -0,0 +1,32 @@ +use alloy_primitives::{address, U256}; +use alloy_sol_types::{sol, SolCall, SolValue}; +use halo2_proofs::halo2curves::bn256::Fr; +use rstest::rstest; +use shielder_rust_sdk::conversion::{address_to_field, field_to_u256}; + +use crate::shielder::deploy::{deployment, Deployment}; + +sol! { + function addressToUInt256(address addr) public pure returns (uint256); +} + +#[rstest] +fn verify_off_chain_and_on_chain_address_to_u256_conversion(mut deployment: Deployment) { + let some_address = address!("f39Fd6e51aad88F6F4ce6aB8827279cffFb92266"); + + let on_chain_result = deployment + .evm + .call( + deployment.contract_suite.shielder, + addressToUInt256Call { addr: some_address }.abi_encode(), + None, + None, + ) + .expect("Failed to convert address to field on-chain"); + let on_chain = ::abi_decode(&on_chain_result.output, true) + .expect("Failed to decode on-chain result"); + + let off_chain = field_to_u256(address_to_field::(some_address)); + + assert_eq!(on_chain, off_chain); +} diff --git a/crates/integration-tests/src/shielder/calls/deposit_native.rs b/crates/integration-tests/src/shielder/calls/deposit_native.rs new file mode 100644 index 00000000..53cb61bd --- /dev/null +++ b/crates/integration-tests/src/shielder/calls/deposit_native.rs @@ -0,0 +1,268 @@ +use std::assert_matches::assert_matches; + +use alloy_primitives::{Bytes, TxHash, U256}; +use rstest::rstest; +use shielder_rust_sdk::{ + account::{ + call_data::{DepositCallType, MerkleProof}, + ShielderAccount, + }, + contract::ShielderContract::{ + depositNativeCall, DepositNative, ShielderContractErrors, ShielderContractEvents, + }, +}; + +use crate::shielder::{ + actor_balance_decreased_by, + calls::new_account_native, + deploy::{deployment, Deployment}, + invoke_shielder_call, + limits::{get_deposit_limit, set_deposit_limit}, + merkle::get_merkle_args, + CallResult, +}; + +pub fn prepare_call( + deployment: &mut Deployment, + shielder_account: &mut ShielderAccount, + amount: U256, +) -> (depositNativeCall, U256) { + let note_index = shielder_account + .current_leaf_index() + .expect("No leaf index"); + + let (params, pk) = deployment.deposit_native_proving_params.clone(); + let (merkle_root, merkle_path) = get_merkle_args( + deployment.contract_suite.shielder, + note_index, + &mut deployment.evm, + ); + let calldata = shielder_account.prepare_call::( + ¶ms, + &pk, + U256::from(amount), + &MerkleProof { + root: merkle_root, + path: merkle_path, + }, + ); + (calldata, note_index) +} + +pub fn invoke_call( + deployment: &mut Deployment, + shielder_account: &mut ShielderAccount, + amount: U256, + calldata: &depositNativeCall, +) -> CallResult { + let call_result = invoke_shielder_call(deployment, calldata, Some(amount)); + + match call_result { + Ok(event) => { + shielder_account.register_action((TxHash::default(), event.clone())); + Ok(event) + } + Err(_) => call_result, + } +} + +#[rstest] +fn succeeds(mut deployment: Deployment) { + let mut shielder_account = + new_account_native::create_account_and_call(&mut deployment, U256::from(1), U256::from(10)) + .unwrap(); + + let amount = U256::from(5); + let (calldata, note_index) = prepare_call(&mut deployment, &mut shielder_account, amount); + let result = invoke_call(&mut deployment, &mut shielder_account, amount, &calldata); + + assert_eq!( + result, + Ok(ShielderContractEvents::DepositNative(DepositNative { + idHiding: calldata.idHiding, + amount: U256::from(amount), + newNote: calldata.newNote, + newNoteIndex: note_index.saturating_add(U256::from(1)), + })) + ); + assert!(actor_balance_decreased_by(&deployment, U256::from(15))); + assert_eq!(shielder_account.shielded_amount, U256::from(15)) +} + +#[rstest] +fn can_consume_entire_contract_balance_limit(mut deployment: Deployment) { + let mut shielder_account = new_account_native::create_account_and_call( + &mut deployment, + U256::from(1), + U256::from((1u128 << 112) - 2), + ) + .unwrap(); + + let amount = U256::from(1); + let (calldata, _) = prepare_call(&mut deployment, &mut shielder_account, amount); + let result = invoke_call(&mut deployment, &mut shielder_account, amount, &calldata); + + assert!(result.is_ok()); + assert!(actor_balance_decreased_by( + &deployment, + U256::from((1u128 << 112) - 1) + )) +} + +#[rstest] +fn fails_if_contract_balance_limit_reached(mut deployment: Deployment) { + let mut shielder_account = new_account_native::create_account_and_call( + &mut deployment, + U256::from(1), + U256::from((1u128 << 112) - 1), + ) + .unwrap(); + + let amount = U256::from(1); + let (calldata, _) = prepare_call(&mut deployment, &mut shielder_account, amount); + let result = invoke_call(&mut deployment, &mut shielder_account, amount, &calldata); + + assert_matches!( + result, + Err(ShielderContractErrors::ContractBalanceLimitReached(_)) + ); + assert!(actor_balance_decreased_by( + &deployment, + U256::from((1u128 << 112) - 1) + )) +} + +#[rstest] +fn correctly_handles_max_u256_value(mut deployment: Deployment) { + let initial_amount = U256::from(10); + let mut shielder_account = + new_account_native::create_account_and_call(&mut deployment, U256::from(1), initial_amount) + .unwrap(); + + let amount = U256::MAX - initial_amount; + let (calldata, _) = prepare_call(&mut deployment, &mut shielder_account, amount); + let result = invoke_call(&mut deployment, &mut shielder_account, amount, &calldata); + + assert_matches!( + result, + Err(ShielderContractErrors::ContractBalanceLimitReached(_)) + ); + assert!(actor_balance_decreased_by(&deployment, U256::from(10))) +} + +#[rstest] +fn cannot_use_same_note_twice(mut deployment: Deployment) { + let mut shielder_account = + new_account_native::create_account_and_call(&mut deployment, U256::from(1), U256::from(10)) + .unwrap(); + + let amount = U256::from(5); + let (calldata, _) = prepare_call(&mut deployment, &mut shielder_account, amount); + let result_1 = invoke_call(&mut deployment, &mut shielder_account, amount, &calldata); + assert!(result_1.is_ok()); + + let result_2 = invoke_call(&mut deployment, &mut shielder_account, amount, &calldata); + + assert_matches!( + result_2, + Err(ShielderContractErrors::DuplicatedNullifier(_)) + ); + assert!(actor_balance_decreased_by(&deployment, U256::from(15))) +} + +#[rstest] +fn fails_if_merkle_root_does_not_exist(mut deployment: Deployment) { + let mut shielder_account = ShielderAccount::default(); + + let calldata = depositNativeCall { + idHiding: U256::ZERO, + oldNullifierHash: U256::ZERO, + newNote: U256::ZERO, + merkleRoot: U256::ZERO, + proof: Bytes::from(vec![]), + }; + let result = invoke_call( + &mut deployment, + &mut shielder_account, + U256::from(10), + &calldata, + ); + + assert_matches!( + result, + Err(ShielderContractErrors::MerkleRootDoesNotExist(_)) + ); + assert!(actor_balance_decreased_by(&deployment, U256::ZERO)) +} + +#[rstest] +fn fails_if_proof_incorrect(mut deployment: Deployment) { + let mut shielder_account = + new_account_native::create_account_and_call(&mut deployment, U256::from(1), U256::from(10)) + .unwrap(); + + let amount = U256::from(5); + let (mut calldata, _) = prepare_call(&mut deployment, &mut shielder_account, amount); + calldata.proof = Bytes::from(vec![]); + let result = invoke_call(&mut deployment, &mut shielder_account, amount, &calldata); + + assert_matches!( + result, + Err(ShielderContractErrors::DepositVerificationFailed(_)) + ); + assert!(actor_balance_decreased_by(&deployment, U256::from(10))) +} + +#[rstest] +fn rejects_value_zero(mut deployment: Deployment) { + let initial_amount = U256::from(10); + let mut shielder_account = + new_account_native::create_account_and_call(&mut deployment, U256::from(1), initial_amount) + .unwrap(); + + let amount = U256::ZERO; + let (calldata, _) = prepare_call(&mut deployment, &mut shielder_account, amount); + let result = invoke_call(&mut deployment, &mut shielder_account, amount, &calldata); + + assert_matches!(result, Err(ShielderContractErrors::ZeroAmount(_))); + assert!(actor_balance_decreased_by(&deployment, U256::from(10))) +} + +#[rstest] +fn fails_if_over_deposit_limit(mut deployment: Deployment) { + let initial_amount = U256::from(101); + let mut shielder_account = + new_account_native::create_account_and_call(&mut deployment, U256::from(1), initial_amount) + .unwrap(); + + let amount = U256::from(1); + let (calldata, _) = prepare_call(&mut deployment, &mut shielder_account, amount); + let result = invoke_call(&mut deployment, &mut shielder_account, amount, &calldata); + + assert!(result.is_ok()); + + let old_limit = get_deposit_limit(&mut deployment); + + assert_eq!(old_limit, U256::MAX); + + let new_limit = U256::from(100); + set_deposit_limit(&mut deployment, new_limit); + + let returned_new_limit = get_deposit_limit(&mut deployment); + + assert_eq!(returned_new_limit, U256::from(100)); + + let initial_amount = U256::from(10); + let mut shielder_account = + new_account_native::create_account_and_call(&mut deployment, U256::from(2), initial_amount) + .unwrap(); + + let amount = U256::from(101); + let (calldata, _) = prepare_call(&mut deployment, &mut shielder_account, amount); + let result = invoke_call(&mut deployment, &mut shielder_account, amount, &calldata); + + assert_matches!( + result, + Err(ShielderContractErrors::AmountOverDepositLimit(_)) + ) +} diff --git a/crates/integration-tests/src/shielder/calls/domain_separator.rs b/crates/integration-tests/src/shielder/calls/domain_separator.rs new file mode 100644 index 00000000..3ef0b40c --- /dev/null +++ b/crates/integration-tests/src/shielder/calls/domain_separator.rs @@ -0,0 +1,27 @@ +use alloy_primitives::U256; +use rstest::rstest; +use shielder_rust_sdk::permit2::get_domain_separator; + +use crate::{ + permit2, + shielder::deploy::{deployment, Deployment}, +}; + +#[rstest] +fn domain_separator(mut deployment: Deployment) { + let expected = deployment + .evm + .call( + deployment.contract_suite.permit2, + permit2::domain_separator_calldata(), + None, + None, + ) + .expect("Permit2 DOMAIN_SEPARATOR call failed") + .output; + + assert_eq!( + get_domain_separator(U256::from(1), deployment.contract_suite.permit2).to_vec(), + expected + ); +} diff --git a/crates/integration-tests/src/shielder/calls/mod.rs b/crates/integration-tests/src/shielder/calls/mod.rs new file mode 100644 index 00000000..7cedc55c --- /dev/null +++ b/crates/integration-tests/src/shielder/calls/mod.rs @@ -0,0 +1,4 @@ +pub mod deposit_native; +pub mod domain_separator; +pub mod new_account_native; +pub mod withdraw_native; diff --git a/crates/integration-tests/src/shielder/calls/new_account_native.rs b/crates/integration-tests/src/shielder/calls/new_account_native.rs new file mode 100644 index 00000000..d718e431 --- /dev/null +++ b/crates/integration-tests/src/shielder/calls/new_account_native.rs @@ -0,0 +1,177 @@ +use std::assert_matches::assert_matches; + +use alloy_primitives::{TxHash, U256}; +use rstest::rstest; +use shielder_rust_sdk::{ + account::{call_data::NewAccountCallType, ShielderAccount}, + contract::ShielderContract::{ + newAccountNativeCall, NewAccountNative, ShielderContractErrors, ShielderContractEvents, + }, +}; + +use crate::shielder::{ + actor_balance_decreased_by, deployment, invoke_shielder_call, + limits::{get_deposit_limit, set_deposit_limit}, + CallResult, Deployment, +}; + +pub fn prepare_call( + deployment: &mut Deployment, + shielder_account: &mut ShielderAccount, + amount: U256, +) -> newAccountNativeCall { + let (params, pk) = deployment.new_account_native_proving_params.clone(); + shielder_account.prepare_call::(¶ms, &pk, amount, &()) +} + +pub fn invoke_call( + deployment: &mut Deployment, + shielder_account: &mut ShielderAccount, + amount: U256, + calldata: &newAccountNativeCall, +) -> CallResult { + let call_result = invoke_shielder_call(deployment, calldata, Some(amount)); + + match call_result { + Ok(event) => { + shielder_account.register_action((TxHash::default(), event.clone())); + Ok(event) + } + Err(_) => call_result, + } +} + +pub fn create_account_and_call( + deployment: &mut Deployment, + id: U256, + initial_amount: U256, +) -> Result { + let mut shielder_account = ShielderAccount::new(id); + + let calldata = prepare_call(deployment, &mut shielder_account, initial_amount); + let result = invoke_call(deployment, &mut shielder_account, initial_amount, &calldata); + + match result { + Ok(_) => Ok(shielder_account), + Err(e) => Err(e), + } +} + +#[rstest] +fn succeeds(mut deployment: Deployment) { + let mut shielder_account = ShielderAccount::default(); + let amount = U256::from(10); + let calldata = prepare_call(&mut deployment, &mut shielder_account, amount); + + let result = invoke_call(&mut deployment, &mut shielder_account, amount, &calldata); + + assert_eq!( + result, + Ok(ShielderContractEvents::NewAccountNative(NewAccountNative { + idHash: calldata.idHash, + amount, + newNote: calldata.newNote, + newNoteIndex: U256::ZERO, + })) + ); + assert!(actor_balance_decreased_by(&deployment, amount)); + assert_eq!(shielder_account.shielded_amount, U256::from(amount)) +} + +#[rstest] +fn cannot_use_same_id_twice(mut deployment: Deployment) { + assert!(create_account_and_call(&mut deployment, U256::from(1), U256::from(10)).is_ok()); + + let result = create_account_and_call(&mut deployment, U256::from(1), U256::from(10)); + + assert_matches!(result, Err(ShielderContractErrors::DuplicatedNullifier(_))); + assert!(actor_balance_decreased_by(&deployment, U256::from(10))) +} + +#[rstest] +fn can_consume_entire_contract_balance_limit(mut deployment: Deployment) { + let mut shielder_account = ShielderAccount::default(); + let amount = U256::from((1u128 << 112) - 1); + let calldata = prepare_call(&mut deployment, &mut shielder_account, amount); + + let result = invoke_call(&mut deployment, &mut shielder_account, amount, &calldata); + + assert!(result.is_ok()); + assert_matches!(result.unwrap(), ShielderContractEvents::NewAccountNative(_)); + assert!(actor_balance_decreased_by(&deployment, amount)) +} + +#[rstest] +fn fails_if_contract_balance_limit_reached(mut deployment: Deployment) { + let amount_1 = U256::from((1u128 << 112) - 1); + assert!(create_account_and_call(&mut deployment, U256::from(1), amount_1).is_ok()); + + let amount_2 = U256::from(1); + let result_2 = create_account_and_call(&mut deployment, U256::from(2), amount_2); + + assert_matches!( + result_2, + Err(ShielderContractErrors::ContractBalanceLimitReached(_)) + ); + assert!(actor_balance_decreased_by(&deployment, amount_1)) +} + +#[rstest] +fn correctly_handles_max_u256_value(mut deployment: Deployment) { + let result = create_account_and_call(&mut deployment, U256::from(1), U256::MAX); + + assert_matches!( + result, + Err(ShielderContractErrors::ContractBalanceLimitReached(_)) + ); + assert!(actor_balance_decreased_by(&deployment, U256::ZERO)) +} + +#[rstest] +fn fails_if_proof_incorrect(mut deployment: Deployment) { + let mut shielder_account = ShielderAccount::default(); + let amount = U256::from(10); + let mut calldata = prepare_call(&mut deployment, &mut shielder_account, amount); + calldata.idHash = calldata.idHash.wrapping_add(U256::from(1)); + + let result = invoke_call(&mut deployment, &mut shielder_account, amount, &calldata); + + assert_matches!( + result, + Err(ShielderContractErrors::NewAccountVerificationFailed(_)) + ); + assert!(actor_balance_decreased_by(&deployment, U256::ZERO)) +} + +#[rstest] +fn fails_if_over_deposit_limit(mut deployment: Deployment) { + let mut shielder_account = ShielderAccount::default(); + let amount = U256::from(101); + let calldata = prepare_call(&mut deployment, &mut shielder_account, amount); + + let result = invoke_call(&mut deployment, &mut shielder_account, amount, &calldata); + + assert!(result.is_ok()); + + let old_limit = get_deposit_limit(&mut deployment); + + assert_eq!(old_limit, U256::MAX); + + let new_limit = U256::from(100); + set_deposit_limit(&mut deployment, new_limit); + + let returned_new_limit = get_deposit_limit(&mut deployment); + + assert_eq!(returned_new_limit, new_limit); + + let mut shielder_account = ShielderAccount::default(); + let amount = U256::from(101); + let calldata = prepare_call(&mut deployment, &mut shielder_account, amount); + + let result = invoke_call(&mut deployment, &mut shielder_account, amount, &calldata); + + assert_matches!( + result, + Err(ShielderContractErrors::AmountOverDepositLimit(_)) + ) +} diff --git a/crates/integration-tests/src/shielder/calls/withdraw_native.rs b/crates/integration-tests/src/shielder/calls/withdraw_native.rs new file mode 100644 index 00000000..713c34a5 --- /dev/null +++ b/crates/integration-tests/src/shielder/calls/withdraw_native.rs @@ -0,0 +1,361 @@ +use std::{assert_matches::assert_matches, str::FromStr}; + +use alloy_primitives::{Address, Bytes, TxHash, U256}; +use rstest::rstest; +use shielder_rust_sdk::{ + account::{ + call_data::{MerkleProof, WithdrawCallType, WithdrawExtra}, + ShielderAccount, + }, + contract::ShielderContract::{ + withdrawNativeCall, ShielderContractErrors, ShielderContractEvents, WithdrawNative, + }, + version::ContractVersion, +}; + +use crate::shielder::{ + actor_balance_decreased_by, + calls::{deposit_native, new_account_native}, + deploy::{deployment, Deployment, RECIPIENT_ADDRESS, RELAYER_ADDRESS, REVERTING_ADDRESS}, + destination_balances_unchanged, invoke_shielder_call, + merkle::get_merkle_args, + recipient_balance_increased_by, relayer_balance_increased_by, CallResult, +}; + +struct PrepareCallArgs { + amount: U256, + withdraw_address: Address, + relayer_address: Address, + relayer_fee: U256, +} + +fn prepare_args(amount: U256, relayer_fee: U256) -> PrepareCallArgs { + PrepareCallArgs { + amount, + withdraw_address: Address::from_str(RECIPIENT_ADDRESS).unwrap(), + relayer_address: Address::from_str(RELAYER_ADDRESS).unwrap(), + relayer_fee, + } +} + +fn prepare_call( + deployment: &mut Deployment, + shielder_account: &mut ShielderAccount, + args: PrepareCallArgs, +) -> (withdrawNativeCall, U256) { + let note_index = shielder_account + .current_leaf_index() + .expect("No leaf index"); + + let (params, pk) = deployment.withdraw_native_proving_params.clone(); + let (merkle_root, merkle_path) = get_merkle_args( + deployment.contract_suite.shielder, + note_index, + &mut deployment.evm, + ); + + let calldata = shielder_account.prepare_call::( + ¶ms, + &pk, + U256::from(args.amount), + &WithdrawExtra { + merkle_proof: MerkleProof { + root: merkle_root, + path: merkle_path, + }, + to: args.withdraw_address, + relayer_address: args.relayer_address, + relayer_fee: args.relayer_fee, + contract_version: ContractVersion { + note_version: 0, + circuit_version: 0, + patch_version: 1, + }, + }, + ); + + (calldata, note_index) +} + +fn invoke_call( + deployment: &mut Deployment, + shielder_account: &mut ShielderAccount, + calldata: &withdrawNativeCall, +) -> CallResult { + let call_result = invoke_shielder_call(deployment, calldata, None); + + match call_result { + Ok(event) => { + shielder_account.register_action((TxHash::default(), event.clone())); + Ok(event) + } + Err(_) => call_result, + } +} + +#[rstest] +fn succeeds(mut deployment: Deployment) { + let mut shielder_account = + new_account_native::create_account_and_call(&mut deployment, U256::from(1), U256::from(20)) + .unwrap(); + + let (withdraw_calldata, withdraw_note_index) = prepare_call( + &mut deployment, + &mut shielder_account, + prepare_args(U256::from(5), U256::from(1)), + ); + let withdraw_result = invoke_call(&mut deployment, &mut shielder_account, &withdraw_calldata); + + assert_eq!( + withdraw_result, + Ok(ShielderContractEvents::WithdrawNative(WithdrawNative { + idHiding: withdraw_calldata.idHiding, + amount: U256::from(5), + withdrawAddress: Address::from_str(RECIPIENT_ADDRESS).unwrap(), + newNote: withdraw_calldata.newNote, + relayerAddress: Address::from_str(RELAYER_ADDRESS).unwrap(), + newNoteIndex: withdraw_note_index.saturating_add(U256::from(1)), + fee: U256::from(1), + })) + ); + assert!(actor_balance_decreased_by(&deployment, U256::from(20))); + assert!(recipient_balance_increased_by(&deployment, U256::from(4))); + assert!(relayer_balance_increased_by(&deployment, U256::from(1))); + assert_eq!(shielder_account.shielded_amount, U256::from(15)) +} + +#[rstest] +fn succeeds_after_deposit(mut deployment: Deployment) { + let mut shielder_account = + new_account_native::create_account_and_call(&mut deployment, U256::from(1), U256::from(20)) + .unwrap(); + + let deposit_amount = U256::from(10); + let (deposit_calldata, _) = + deposit_native::prepare_call(&mut deployment, &mut shielder_account, deposit_amount); + deposit_native::invoke_call( + &mut deployment, + &mut shielder_account, + deposit_amount, + &deposit_calldata, + ) + .unwrap(); + + let (withdraw_calldata, withdraw_note_index) = prepare_call( + &mut deployment, + &mut shielder_account, + prepare_args(U256::from(5), U256::from(1)), + ); + let withdraw_result = invoke_call(&mut deployment, &mut shielder_account, &withdraw_calldata); + + assert_eq!( + withdraw_result, + Ok(ShielderContractEvents::WithdrawNative(WithdrawNative { + idHiding: withdraw_calldata.idHiding, + amount: U256::from(5), + withdrawAddress: Address::from_str(RECIPIENT_ADDRESS).unwrap(), + newNote: withdraw_calldata.newNote, + relayerAddress: Address::from_str(RELAYER_ADDRESS).unwrap(), + newNoteIndex: withdraw_note_index.saturating_add(U256::from(1)), + fee: U256::from(1), + })) + ); + assert!(actor_balance_decreased_by(&deployment, U256::from(30))); + assert!(recipient_balance_increased_by(&deployment, U256::from(4))); + assert!(relayer_balance_increased_by(&deployment, U256::from(1))); + assert_eq!(shielder_account.shielded_amount, U256::from(25)) +} + +#[rstest] +fn fails_if_proof_incorrect(mut deployment: Deployment) { + let mut shielder_account = + new_account_native::create_account_and_call(&mut deployment, U256::from(1), U256::from(20)) + .unwrap(); + + let (mut calldata, _) = prepare_call( + &mut deployment, + &mut shielder_account, + prepare_args(U256::from(5), U256::from(1)), + ); + calldata.newNote = calldata.newNote.wrapping_add(U256::from(1)); + + let result = invoke_call(&mut deployment, &mut shielder_account, &calldata); + + assert_matches!( + result, + Err(ShielderContractErrors::WithdrawVerificationFailed(_)) + ); + assert!(actor_balance_decreased_by(&deployment, U256::from(20))); + assert!(destination_balances_unchanged(&deployment)) +} + +#[rstest] +fn rejects_value_zero(mut deployment: Deployment) { + let mut shielder_account = + new_account_native::create_account_and_call(&mut deployment, U256::from(1), U256::from(20)) + .unwrap(); + + let (calldata, _) = prepare_call( + &mut deployment, + &mut shielder_account, + prepare_args(U256::from(0), U256::from(1)), + ); + let result = invoke_call(&mut deployment, &mut shielder_account, &calldata); + + assert_matches!(result, Err(ShielderContractErrors::ZeroAmount(_))); + assert!(actor_balance_decreased_by(&deployment, U256::from(20))); + assert!(destination_balances_unchanged(&deployment)) +} + +#[rstest] +fn fails_if_fee_higher_than_amount(mut deployment: Deployment) { + let mut shielder_account = + new_account_native::create_account_and_call(&mut deployment, U256::from(1), U256::from(20)) + .unwrap(); + + let (calldata, _) = prepare_call( + &mut deployment, + &mut shielder_account, + prepare_args(U256::from(3), U256::from(3)), + ); + let result = invoke_call(&mut deployment, &mut shielder_account, &calldata); + + assert_matches!(result, Err(ShielderContractErrors::FeeHigherThanAmount(_))); + assert!(actor_balance_decreased_by(&deployment, U256::from(20))); + assert!(destination_balances_unchanged(&deployment)) +} + +#[rstest] +fn accepts_max_amount(mut deployment: Deployment) { + let mut shielder_account = new_account_native::create_account_and_call( + &mut deployment, + U256::from(1), + U256::from((1u128 << 112) - 1), + ) + .unwrap(); + + let (calldata, _) = prepare_call( + &mut deployment, + &mut shielder_account, + prepare_args(U256::from((1u128 << 112) - 1), U256::from(1)), + ); + let result = invoke_call(&mut deployment, &mut shielder_account, &calldata); + + assert!(result.is_ok()); + assert!(actor_balance_decreased_by( + &deployment, + U256::from((1u128 << 112) - 1) + )); + assert!(recipient_balance_increased_by( + &deployment, + U256::from((1u128 << 112) - 2) + )); + assert!(relayer_balance_increased_by(&deployment, U256::from(1))) +} + +#[rstest] +fn rejects_too_high_amount(mut deployment: Deployment) { + let mut shielder_account = + new_account_native::create_account_and_call(&mut deployment, U256::from(1), U256::from(20)) + .unwrap(); + + let (mut calldata, _) = prepare_call( + &mut deployment, + &mut shielder_account, + prepare_args(U256::from(2), U256::from(1)), + ); + calldata.amount = U256::from(1u128 << 112); + let result = invoke_call(&mut deployment, &mut shielder_account, &calldata); + + assert_matches!(result, Err(ShielderContractErrors::AmountTooHigh(_))); + assert!(actor_balance_decreased_by(&deployment, U256::from(20))); + assert!(destination_balances_unchanged(&deployment)) +} + +#[rstest] +fn fails_if_merkle_root_does_not_exist(mut deployment: Deployment) { + let mut shielder_account = ShielderAccount::default(); + + let calldata = withdrawNativeCall { + idHiding: U256::ZERO, + withdrawAddress: Address::from_str(RECIPIENT_ADDRESS).unwrap(), + relayerAddress: Address::from_str(RELAYER_ADDRESS).unwrap(), + relayerFee: U256::ZERO, + amount: U256::from(10), + merkleRoot: U256::ZERO, + oldNullifierHash: U256::ZERO, + newNote: U256::ZERO, + proof: Bytes::from(vec![]), + }; + let result = invoke_call(&mut deployment, &mut shielder_account, &calldata); + + assert_matches!( + result, + Err(ShielderContractErrors::MerkleRootDoesNotExist(_)) + ); + assert!(actor_balance_decreased_by(&deployment, U256::from(0))); + assert!(destination_balances_unchanged(&deployment)) +} + +#[rstest] +fn cannot_use_same_note_twice(mut deployment: Deployment) { + let mut shielder_account = + new_account_native::create_account_and_call(&mut deployment, U256::from(1), U256::from(20)) + .unwrap(); + + let (calldata, _) = prepare_call( + &mut deployment, + &mut shielder_account, + prepare_args(U256::from(5), U256::from(1)), + ); + assert!(invoke_call(&mut deployment, &mut shielder_account, &calldata).is_ok()); + + let result = invoke_call(&mut deployment, &mut shielder_account, &calldata); + + assert_matches!(result, Err(ShielderContractErrors::DuplicatedNullifier(_))); + assert!(actor_balance_decreased_by(&deployment, U256::from(20))); + assert!(recipient_balance_increased_by(&deployment, U256::from(4))); + assert!(relayer_balance_increased_by(&deployment, U256::from(1))) +} + +#[rstest] +fn handles_withdraw_transfer_failure(mut deployment: Deployment) { + let mut shielder_account = + new_account_native::create_account_and_call(&mut deployment, U256::from(1), U256::from(20)) + .unwrap(); + + let (calldata, _) = prepare_call( + &mut deployment, + &mut shielder_account, + PrepareCallArgs { + withdraw_address: Address::from_str(REVERTING_ADDRESS).unwrap(), + ..prepare_args(U256::from(5), U256::from(1)) + }, + ); + let result = invoke_call(&mut deployment, &mut shielder_account, &calldata); + + assert_matches!(result, Err(ShielderContractErrors::NativeTransferFailed(_))); + assert!(actor_balance_decreased_by(&deployment, U256::from(20))); + assert!(destination_balances_unchanged(&deployment)) +} + +#[rstest] +fn handles_fee_transfer_failure(mut deployment: Deployment) { + let mut shielder_account = + new_account_native::create_account_and_call(&mut deployment, U256::from(1), U256::from(20)) + .unwrap(); + + let (calldata, _) = prepare_call( + &mut deployment, + &mut shielder_account, + PrepareCallArgs { + relayer_address: Address::from_str(REVERTING_ADDRESS).unwrap(), + ..prepare_args(U256::from(5), U256::from(1)) + }, + ); + let result = invoke_call(&mut deployment, &mut shielder_account, &calldata); + + assert_matches!(result, Err(ShielderContractErrors::NativeTransferFailed(_))); + assert!(actor_balance_decreased_by(&deployment, U256::from(20))); + assert!(destination_balances_unchanged(&deployment)) +} diff --git a/crates/integration-tests/src/shielder/deploy.rs b/crates/integration-tests/src/shielder/deploy.rs new file mode 100644 index 00000000..8c00a49a --- /dev/null +++ b/crates/integration-tests/src/shielder/deploy.rs @@ -0,0 +1,246 @@ +use std::str::FromStr; + +use alloy_primitives::{keccak256, Address, Bytes, U256}; +use alloy_sol_types::{SolCall, SolConstructor}; +use evm_utils::{ + compilation::source_to_bytecode, + revm_primitives::{AccountInfo, Bytecode}, + EvmRunner, +}; +use rstest::{fixture, rstest}; +use shielder_rust_sdk::contract::ShielderContract::initializeCall; + +use crate::{ + deploy_contract, + permit2::PERMIT2_BYTECODE, + proving_utils::{ + deposit_native_proving_params, new_account_native_proving_params, + withdraw_native_proving_params, ProvingParams, + }, + read_contract, + shielder::{ + erc1967proxy::{self, ERC_1967_PROXY_BYTECODE}, + unpause_shielder, + }, + token, + verifier::{deploy_verifiers_and_keys, VerificationContracts}, +}; + +/// The address of the deployer account. +/// +/// This is one of the default accounts in the Anvil testnet. +pub const DEPLOYER_ADDRESS: &str = "f39Fd6e51aad88F6F4ce6aB8827279cffFb92266"; +pub const DEPLOYER_INITIAL_BALANCE: U256 = U256::MAX; + +/// The address of the actor account. +/// +/// This is one of the default accounts in the Anvil testnet. +pub const ACTOR_ADDRESS: &str = "70997970C51812dc3A010C7d01b50e0d17dc79C8"; +pub const ACTOR_INITIAL_BALANCE: U256 = U256::MAX; + +/// The private key of the actor account. +pub const ACTOR_PRIVATE_KEY: &str = + "0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d"; + +pub const RECIPIENT_ADDRESS: &str = "70997970C51812dc3A010C7d01b50e0d17dc79C9"; +pub const RECIPIENT_INITIAL_BALANCE: U256 = U256::ZERO; + +pub const RELAYER_ADDRESS: &str = "70997970C51812dc3A010C7d01b50e0d17dc79CA"; +pub const RELAYER_INITIAL_BALANCE: U256 = U256::ZERO; + +// Will always revert when receiving funds. +pub const REVERTING_ADDRESS: &str = "70997970C51812dc3A010C7d01b50e0d17dc79CB"; +pub const REVERTING_ADDRESS_INITIAL_BALANCE: U256 = U256::ZERO; +pub const REVERTING_BYTECODE: [u8; 4] = [0x60, 0x00, 0x80, 0xfd]; // PUSH1 0x00 DUP1 REVERT + +pub const INITIAL_DEPOSIT_LIMIT: U256 = U256::MAX; + +/// Contains full deployment addresses. +pub struct ShielderContractSuite { + pub permit2: Address, + pub shielder: Address, + pub token: Address, +} + +pub fn prepare_account( + evm: &mut EvmRunner, + address: &str, + balance: U256, + code: Option, +) -> Address { + let caller = Address::from_str(address).unwrap(); + evm.db.insert_account_info( + caller, + AccountInfo { + nonce: 0_u64, + balance, + code_hash: keccak256(Bytes::new()), + code, + }, + ); + caller +} + +/// Solc leaves this placeholder for a Poseidon2 contract address. +const POSEIDON2_LIB_PLACEHOLDER: &str = "__$fa7e1b6d9a16949b5fb8159594c1e0b34c$__"; + +pub struct Deployment { + pub evm: EvmRunner, + pub contract_suite: ShielderContractSuite, + pub new_account_native_proving_params: ProvingParams, + pub deposit_native_proving_params: ProvingParams, + pub withdraw_native_proving_params: ProvingParams, +} + +/// Deploy whole Shielder suite. +#[fixture] +pub fn deployment( + new_account_native_proving_params: &ProvingParams, + deposit_native_proving_params: &ProvingParams, + withdraw_native_proving_params: &ProvingParams, +) -> Deployment { + let mut evm = EvmRunner::aleph_evm(); + let owner = prepare_account(&mut evm, DEPLOYER_ADDRESS, DEPLOYER_INITIAL_BALANCE, None); + let actor = prepare_account(&mut evm, ACTOR_ADDRESS, ACTOR_INITIAL_BALANCE, None); + prepare_account(&mut evm, RECIPIENT_ADDRESS, RECIPIENT_INITIAL_BALANCE, None); + prepare_account(&mut evm, RELAYER_ADDRESS, RELAYER_INITIAL_BALANCE, None); + let reverting_bytecode = Bytecode::new_raw(Bytes::from_static(&REVERTING_BYTECODE)); + prepare_account( + &mut evm, + REVERTING_ADDRESS, + REVERTING_ADDRESS_INITIAL_BALANCE, + Some(reverting_bytecode), + ); + + let verification_contracts = deploy_verifiers_and_keys(&mut evm); + let token = deploy_token(&mut evm, owner); + let permit2 = deploy_permit2(&mut evm, owner); + let shielder_address = deploy_shielder_contract(verification_contracts, &mut evm, owner); + unpause_shielder(shielder_address, &mut evm); + instrument_token(&mut evm, owner, actor, token, permit2); + + Deployment { + evm, + contract_suite: ShielderContractSuite { + token, + permit2, + shielder: shielder_address, + }, + new_account_native_proving_params: new_account_native_proving_params.clone(), + deposit_native_proving_params: deposit_native_proving_params.clone(), + withdraw_native_proving_params: withdraw_native_proving_params.clone(), + } +} + +/// Deploy ERC20 token contract +fn deploy_token(evm: &mut EvmRunner, caller: Address) -> Address { + let solidity_code = read_contract("Token.sol"); + let compiled_bytecode = source_to_bytecode(solidity_code, "Token", true); + + let constructor_calldata = token::constructor_calldata(U256::from(1000000)); + let calldata = [compiled_bytecode, constructor_calldata].concat(); + + evm.create(calldata, Some(caller)) + .expect("Failed to deploy the Token contract") +} + +/// Performs basic instrumentation: +/// - Transfer an initial amount of ERC20 to the actor account +/// - Approve Permit2 as spender +fn instrument_token( + evm: &mut EvmRunner, + owner: Address, + actor: Address, + token: Address, + permit2: Address, +) { + evm.call( + token, + token::transfer_calldata(actor, U256::from(100000)), + Some(owner), + None, + ) + .expect("ERC20 transfer call failed"); + + evm.call( + token, + token::approve_calldata(permit2, U256::MAX), + Some(actor), + None, + ) + .expect("ERC20 approve call failed"); +} + +/// deploy Permit2 contract from a pre-compiled bytecode. +fn deploy_permit2(evm: &mut EvmRunner, caller: Address) -> Address { + let bytecode = hex::decode(PERMIT2_BYTECODE).expect("Failed to decode permit2 bytecode"); + evm.create(bytecode, Some(caller)) + .expect("Failed to deploy Shielder implementation contract") +} + +/// Deploys the Shielder implementation contract. +/// +/// This requires more steps than deploying a regular contract because Solc leaves placeholders +/// in the bytecode, which has to be replaced with a deployed Poseidon2 contract address. +fn deploy_shielder_implementation(evm: &mut EvmRunner) -> Address { + // 1. Compile the Shielder implementation contract. It will contain placeholders. + let solidity_code = read_contract("Shielder.sol"); + let implementation_bytecode = source_to_bytecode(solidity_code, "Shielder", false); + + // 2. Compile and deploy auxiliary contracts. + let poseidon2_address = + deploy_contract("Poseidon2T8Assembly.sol", "Poseidon2T8Assembly", evm).to_string(); + + // 3. Manipulate the Shielder implementation bytecode to replace the placeholders with the + // corresponding contract addresses. + let implementation_bytecode = String::from_utf8(implementation_bytecode).unwrap(); + let with_poseidon2 = implementation_bytecode.replace( + POSEIDON2_LIB_PLACEHOLDER, + poseidon2_address.strip_prefix("0x").unwrap(), + ); + let ready_bytecode = hex::decode(with_poseidon2).unwrap(); + + // 4. Finally, deploy the Shielder implementation contract. + evm.create(ready_bytecode, None) + .expect("Failed to deploy Shielder implementation contract") +} + +/// Deploy Shielder contract using ERC 1967 proxy. +pub fn deploy_shielder_contract( + verification_contracts: VerificationContracts, + evm: &mut EvmRunner, + owner: Address, +) -> Address { + let implementation_address = deploy_shielder_implementation(evm); + let initialization_data = initializeCall { + initialOwner: owner, + _newAccountVerifier: verification_contracts.new_account_verifier, + _depositVerifier: verification_contracts.deposit_verifier, + _withdrawVerifier: verification_contracts.withdraw_verifier, + _newAccountVerifyingKey: verification_contracts.new_account_vk, + _depositVerifyingKey: verification_contracts.deposit_vk, + _withdrawVerifyingKey: verification_contracts.withdraw_vk, + _depositLimit: INITIAL_DEPOSIT_LIMIT, + } + .abi_encode(); + + let proxy_bytecode = + hex::decode(ERC_1967_PROXY_BYTECODE).expect("Failed to decode proxy bytecode"); + let proxy_calldata = [ + proxy_bytecode, + erc1967proxy::constructorCall { + implementation: implementation_address, + _data: Bytes::from(initialization_data), + } + .abi_encode(), + ] + .concat(); + + evm.create(proxy_calldata, Some(owner)) + .expect("Failed to deploy Shielder contract through a proxy") +} + +#[rstest] +fn deploy_shielder_suite(_deployment: Deployment) { + // Deployment successful. +} diff --git a/crates/integration-tests/src/shielder/erc1967proxy.rs b/crates/integration-tests/src/shielder/erc1967proxy.rs new file mode 100644 index 00000000..787fc95d --- /dev/null +++ b/crates/integration-tests/src/shielder/erc1967proxy.rs @@ -0,0 +1,8 @@ +use alloy_sol_types::sol; + +pub const ERC_1967_PROXY_BYTECODE: &str = + "608060405261028a803803806100148161017e565b92833981019060408183031261017a578051906001600160a01b0382169081830361017a576020810151906001600160401b03821161017a570183601f8201121561017a5780519061006d610068836101b7565b61017e565b948286526020838301011161017a575f5b82811061016557505060205f9185010152813b15610153577f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b031916821790557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b5f80a281511561013c575f8083602061012495519101845af43d15610134573d91610115610068846101b7565b9283523d5f602085013e6101d2565b505b604051605990816102318239f35b6060916101d2565b505034156101265763b398979f60e01b5f5260045ffd5b634c9c8ce360e01b5f5260045260245ffd5b8060208092840101518282890101520161007e565b5f80fd5b6040519190601f01601f191682016001600160401b038111838210176101a357604052565b634e487b7160e01b5f52604160045260245ffd5b6001600160401b0381116101a357601f01601f191660200190565b906101f657508051156101e757805190602001fd5b630a12f52160e11b5f5260045ffd5b81511580610227575b610207575090565b639996b31560e01b5f9081526001600160a01b0391909116600452602490fd5b50803b156101ff56fe60806040527f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc545f9081906001600160a01b0316368280378136915af43d5f803e156048573d5ff35b3d5ffdfea164736f6c634300081a000a"; + +sol! { + constructor(address implementation, bytes memory _data) payable; +} diff --git a/crates/integration-tests/src/shielder/limits.rs b/crates/integration-tests/src/shielder/limits.rs new file mode 100644 index 00000000..61a37f59 --- /dev/null +++ b/crates/integration-tests/src/shielder/limits.rs @@ -0,0 +1,35 @@ +use std::str::FromStr; + +use alloy_primitives::U256; +use alloy_sol_types::{SolCall, SolValue}; +use shielder_rust_sdk::contract::ShielderContract::{depositLimitCall, setDepositLimitCall}; + +use super::deploy::DEPLOYER_ADDRESS; +use crate::{shielder::deploy::Deployment, Address}; + +pub fn set_deposit_limit(deployment: &mut Deployment, limit: U256) { + let calldata = setDepositLimitCall { + _depositLimit: limit, + } + .abi_encode(); + + deployment + .evm + .call( + deployment.contract_suite.shielder, + calldata, + Some(Address::from_str(DEPLOYER_ADDRESS).unwrap()), + None, + ) + .expect("Call failed"); +} + +pub fn get_deposit_limit(deployment: &mut Deployment) -> U256 { + let calldata = depositLimitCall {}.abi_encode(); + let encoded_limit = deployment + .evm + .call(deployment.contract_suite.shielder, calldata, None, None) + .expect("Call failed") + .output; + ::abi_decode(&encoded_limit, true).expect("Decoding failed") +} diff --git a/crates/integration-tests/src/shielder/merkle.rs b/crates/integration-tests/src/shielder/merkle.rs new file mode 100644 index 00000000..ad87513d --- /dev/null +++ b/crates/integration-tests/src/shielder/merkle.rs @@ -0,0 +1,36 @@ +use alloy_primitives::{Address, U256}; +use alloy_sol_types::{SolCall, SolValue}; +use evm_utils::EvmRunner; +use shielder_circuits::consts::merkle_constants::{ARITY, NOTE_TREE_HEIGHT}; +use shielder_rust_sdk::contract::ShielderContract::getMerklePathCall; + +pub fn get_merkle_args( + shielder_address: Address, + note_index: U256, + evm: &mut EvmRunner, +) -> (U256, [[U256; ARITY]; NOTE_TREE_HEIGHT]) { + let calldata = getMerklePathCall { id: note_index }.abi_encode(); + let result = evm + .call(shielder_address, calldata, None, None) + .expect("Call failed") + .output; + let decoded = >::abi_decode(&result, true).expect("Decoding failed"); + reorganize_merkle_path(decoded) +} + +fn reorganize_merkle_path(merkle_path: Vec) -> (U256, [[U256; ARITY]; NOTE_TREE_HEIGHT]) { + assert_eq!(merkle_path.len(), ARITY * NOTE_TREE_HEIGHT + 1); + + let root = *merkle_path.last().expect("Empty merkle path"); + + let mut result = [[U256::ZERO; ARITY]; NOTE_TREE_HEIGHT]; + for (i, element) in merkle_path + .into_iter() + .enumerate() + .take(ARITY * NOTE_TREE_HEIGHT) + { + result[i / ARITY][i % ARITY] = element; + } + + (root, result) +} diff --git a/crates/integration-tests/src/shielder/mod.rs b/crates/integration-tests/src/shielder/mod.rs new file mode 100644 index 00000000..96b69da8 --- /dev/null +++ b/crates/integration-tests/src/shielder/mod.rs @@ -0,0 +1,83 @@ +use std::str::FromStr; + +use alloy_primitives::{Address, U256}; +use alloy_sol_types::{SolCall, SolEventInterface, SolInterface}; +use deploy::{ + deployment, Deployment, ACTOR_ADDRESS, ACTOR_INITIAL_BALANCE, DEPLOYER_ADDRESS, + RECIPIENT_ADDRESS, RECIPIENT_INITIAL_BALANCE, RELAYER_ADDRESS, RELAYER_INITIAL_BALANCE, +}; +use evm_utils::{EvmRunner, EvmRunnerError}; +use shielder_rust_sdk::contract::ShielderContract::{ + unpauseCall, ShielderContractErrors, ShielderContractEvents, +}; + +mod address_conversion; +mod calls; +mod deploy; +mod erc1967proxy; +mod limits; +mod merkle; + +fn unpause_shielder(shielder: Address, evm: &mut EvmRunner) { + evm.call( + shielder, + unpauseCall {}.abi_encode(), + Some(Address::from_str(DEPLOYER_ADDRESS).unwrap()), + None, + ) + .expect("Call failed"); +} + +type CallResult = Result; + +fn invoke_shielder_call( + deployment: &mut Deployment, + calldata: &impl SolCall, + value: Option, +) -> CallResult { + let logs = deployment + .evm + .call( + deployment.contract_suite.shielder, + calldata.abi_encode(), + Some(Address::from_str(ACTOR_ADDRESS).unwrap()), + value, + ) + .map_err(|e| match e { + EvmRunnerError::Revert(e) => { + ShielderContractErrors::abi_decode(e.output().unwrap(), true).unwrap() + } + _ => panic!("Expected EvmRunnerError::Revert"), + })? + .logs; + + assert_eq!(logs.len(), 1); + let event = ShielderContractEvents::decode_log(&logs[0], true).expect("Decoding event failed"); + assert_eq!(event.address, deployment.contract_suite.shielder); + + Ok(event.data) +} + +fn get_balance(deployment: &Deployment, address: &str) -> U256 { + deployment + .evm + .get_balance(Address::from_str(address).unwrap()) + .unwrap() +} + +fn actor_balance_decreased_by(deployment: &Deployment, amount: U256) -> bool { + get_balance(&deployment, ACTOR_ADDRESS) == ACTOR_INITIAL_BALANCE - amount +} + +fn recipient_balance_increased_by(deployment: &Deployment, amount: U256) -> bool { + get_balance(&deployment, RECIPIENT_ADDRESS) == RECIPIENT_INITIAL_BALANCE + amount +} + +fn relayer_balance_increased_by(deployment: &Deployment, amount: U256) -> bool { + get_balance(&deployment, RELAYER_ADDRESS) == RELAYER_INITIAL_BALANCE + amount +} + +fn destination_balances_unchanged(deployment: &Deployment) -> bool { + recipient_balance_increased_by(deployment, U256::ZERO) + && relayer_balance_increased_by(deployment, U256::ZERO) +} diff --git a/crates/integration-tests/src/token.rs b/crates/integration-tests/src/token.rs new file mode 100644 index 00000000..6546ebdf --- /dev/null +++ b/crates/integration-tests/src/token.rs @@ -0,0 +1,25 @@ +use alloy_primitives::{Address, U256}; +use alloy_sol_types::{sol, SolCall, SolConstructor}; + +sol! { + constructor(uint256 initialSupply); + + function approve(address spender, uint256 value) external returns (bool); + + function transfer(address to, uint256 value) external returns (bool); +} + +pub fn constructor_calldata(initial_supply: U256) -> Vec { + constructorCall { + initialSupply: initial_supply, + } + .abi_encode() +} + +pub fn approve_calldata(spender: Address, value: U256) -> Vec { + approveCall { spender, value }.abi_encode() +} + +pub fn transfer_calldata(to: Address, value: U256) -> Vec { + transferCall { to, value }.abi_encode() +} diff --git a/crates/integration-tests/src/verifier.rs b/crates/integration-tests/src/verifier.rs new file mode 100644 index 00000000..c4595871 --- /dev/null +++ b/crates/integration-tests/src/verifier.rs @@ -0,0 +1,161 @@ +use alloy_primitives::Address; +use alloy_sol_types::SolValue; +use evm_utils::EvmRunner; +use halo2_proofs::halo2curves::bn256::Fr; +use halo2_solidity_verifier::verifier_contract; +use shielder_circuits::{ + consts::RANGE_PROOF_CHUNK_SIZE, deposit::DepositProverKnowledge, + new_account::NewAccountProverKnowledge, withdraw::WithdrawProverKnowledge, F, +}; + +use crate::{deploy_contract, proving_utils}; + +const VERIFIER_CONTRACT_NAME: &str = "Halo2Verifier"; +const VK_CONTRACT_NAME: &str = "Halo2VerifyingKey"; + +#[derive(Copy, Clone)] +pub struct VerificationContracts { + pub new_account_verifier: Address, + pub new_account_vk: Address, + pub deposit_verifier: Address, + pub deposit_vk: Address, + pub withdraw_verifier: Address, + pub withdraw_vk: Address, +} + +pub fn deploy_verifiers_and_keys(evm: &mut EvmRunner) -> VerificationContracts { + let new_account_verifier = + deploy_contract("NewAccountVerifier.sol", VERIFIER_CONTRACT_NAME, evm); + let new_account_vk = deploy_contract("NewAccountVerifyingKey.sol", VK_CONTRACT_NAME, evm); + let deposit_verifier = deploy_contract("DepositVerifier.sol", VERIFIER_CONTRACT_NAME, evm); + let deposit_vk = deploy_contract("DepositVerifyingKey.sol", VK_CONTRACT_NAME, evm); + let withdraw_verifier = deploy_contract("WithdrawVerifier.sol", VERIFIER_CONTRACT_NAME, evm); + let withdraw_vk = deploy_contract("WithdrawVerifyingKey.sol", VK_CONTRACT_NAME, evm); + + VerificationContracts { + new_account_verifier, + new_account_vk, + deposit_verifier, + deposit_vk, + withdraw_verifier, + withdraw_vk, + } +} + +#[test] +fn deploy_verification_contracts() { + deploy_verifiers_and_keys(&mut EvmRunner::aleph_evm()); +} + +fn verify_with_contract( + proof: Vec, + pub_input: Vec, + vk_address: Address, + verifier_address: Address, + evm: &mut EvmRunner, +) -> bool { + let calldata = verifier_contract::encode_calldata(vk_address, &proof, &pub_input); + let response = evm + .call(verifier_address, calldata, None, None) + .expect("Call failed") + .output; + ::abi_decode(&response, true).expect("Decoding contract response failed") +} + +#[test] +fn new_account_contract_verification_works() { + let mut evm = EvmRunner::aleph_evm(); + let verification_contracts = deploy_verifiers_and_keys(&mut evm); + + let (proof, pub_input) = proving_utils::prepare_proof::>(); + assert!(verify_with_contract( + proof, + pub_input, + verification_contracts.new_account_vk, + verification_contracts.new_account_verifier, + &mut evm, + )); +} + +#[test] +fn deposit_contract_verification_works() { + let mut evm = EvmRunner::aleph_evm(); + let verification_contracts = deploy_verifiers_and_keys(&mut evm); + + let (proof, pub_input) = + proving_utils::prepare_proof::>(); + assert!(verify_with_contract( + proof, + pub_input, + verification_contracts.deposit_vk, + verification_contracts.deposit_verifier, + &mut evm, + )); +} + +#[test] +fn withdraw_contract_verification_works() { + let mut evm = EvmRunner::aleph_evm(); + let verification_contracts = deploy_verifiers_and_keys(&mut evm); + + let (proof, pub_input) = + proving_utils::prepare_proof::>(); + assert!(verify_with_contract( + proof, + pub_input, + verification_contracts.withdraw_vk, + verification_contracts.withdraw_verifier, + &mut evm, + )); +} + +// Should trigger an early return in `Halo2Verifier`. +#[test] +fn fails_on_empty_proof() { + let mut evm = EvmRunner::aleph_evm(); + let verification_contracts = deploy_verifiers_and_keys(&mut evm); + + assert!(!verify_with_contract( + vec![], + vec![], + verification_contracts.new_account_vk, + verification_contracts.new_account_verifier, + &mut evm, + )); +} + +// Should trigger a late return in `Halo2Verifier`. +#[test] +fn fails_on_proof_with_wrong_input() { + let mut evm = EvmRunner::aleph_evm(); + let verification_contracts = deploy_verifiers_and_keys(&mut evm); + + let (proof, mut pub_input) = proving_utils::prepare_proof::>(); + pub_input[0] += Fr::from(1); + + assert!(!verify_with_contract( + proof, + pub_input, + verification_contracts.new_account_vk, + verification_contracts.new_account_verifier, + &mut evm, + )); +} + +// Should trigger a late return in `Halo2Verifier`. +#[test] +fn fails_on_corrupted_proof() { + let mut evm = EvmRunner::aleph_evm(); + let verification_contracts = deploy_verifiers_and_keys(&mut evm); + + let (mut proof, pub_input) = proving_utils::prepare_proof::>(); + proof[0] = proof[0].wrapping_add(1u8); + + assert!(!verify_with_contract( + proof, + pub_input, + verification_contracts.new_account_vk, + verification_contracts.new_account_verifier, + &mut evm, + )); +} diff --git a/crates/shielder-cli/Cargo.toml b/crates/shielder-cli/Cargo.toml new file mode 100644 index 00000000..dbd12385 --- /dev/null +++ b/crates/shielder-cli/Cargo.toml @@ -0,0 +1,38 @@ +[package] +name = "shielder-cli" +version = "0.1.0" +readme = "README.md" +description = "CLI for interacting with the zkOS Shielder contract" + +edition.workspace = true +authors.workspace = true +homepage.workspace = true +license.workspace = true +categories.workspace = true +repository.workspace = true + +[dependencies] +alloy-contract = { workspace = true } +alloy-eips = { workspace = true } +alloy-network = { workspace = true } +alloy-primitives = { workspace = true } +alloy-provider = { workspace = true } +alloy-rpc-types-eth = { workspace = true } +alloy-signer-local = { workspace = true } +alloy-sol-types = { workspace = true } +anyhow = { workspace = true, default-features = true } +clap = { workspace = true, features = ["derive"] } +inquire = { workspace = true } +rand = { workspace = true } +reqwest = { workspace = true } +serde = { workspace = true, features = ["derive"] } +serde_json = { workspace = true } +shellexpand = { workspace = true } +tokio = { workspace = true, features = ["rt-multi-thread"] } +tracing = { workspace = true } +tracing-subscriber = { workspace = true, features = ["fmt", "json", "env-filter"] } + +content-encryption = { workspace = true, features = ["std"] } +shielder-circuits = { workspace = true } +shielder-relayer = { workspace = true } +shielder-rust-sdk = { workspace = true, features = ["account", "contract", "conversion", "powers_of_tau"] } diff --git a/crates/shielder-cli/Makefile b/crates/shielder-cli/Makefile new file mode 100644 index 00000000..223ad733 --- /dev/null +++ b/crates/shielder-cli/Makefile @@ -0,0 +1,15 @@ +.PHONY: build +build: ## Build the project + @cargo build --release + +.PHONY: test +test: ## Run tests + @cargo test --release + +.PHONY: lint +lint: ## Run clippy and fmt + @cargo clippy --release -- -D warnings + @cargo +nightly fmt --all + +help: ## Displays this help + @awk 'BEGIN {FS = ":.*##"; printf "$(MAKEFILE_NAME)\nUsage:\n make \033[1;36m\033[0m\n\nTargets:\n"} /^[a-zA-Z0-9_-]+:.*?##/ { printf " \033[1;36m%-25s\033[0m %s\n", $$1, $$2 }' $(MAKEFILE_LIST) diff --git a/crates/shielder-cli/src/app_state.rs b/crates/shielder-cli/src/app_state.rs new file mode 100644 index 00000000..4e61b553 --- /dev/null +++ b/crates/shielder-cli/src/app_state.rs @@ -0,0 +1,107 @@ +use std::str::FromStr; + +use alloy_primitives::{Address, U256}; +use alloy_provider::Provider; +use alloy_signer_local::PrivateKeySigner; +use anyhow::anyhow; +use serde::{Deserialize, Serialize}; +use shielder_rust_sdk::{ + account::ShielderAccount, + contract::{ + providers::create_simple_provider, ConnectionPolicy, ShielderContractError, ShielderUser, + }, +}; +use tracing::{debug, warn}; + +/// The URL of the relayer RPC. +#[derive(Clone, Eq, PartialEq, Debug, Default, Deserialize, Serialize)] +pub struct RelayerRpcUrl { + base_url: String, +} + +impl RelayerRpcUrl { + pub fn new(base_url: String) -> Self { + Self { base_url } + } + + pub fn healthcheck_url(&self) -> String { + format!("{}/health", self.base_url) + } + + pub fn relay_url(&self) -> String { + format!("{}/relay", self.base_url) + } + + pub async fn check_connection(&self) -> anyhow::Result<()> { + let response = reqwest::get(self.healthcheck_url()).await?; + if response.status().is_success() { + debug!("Relayer healthcheck succeeded."); + Ok(()) + } else { + warn!("Relayer healthcheck failed."); + Err(anyhow!("Relayer healthcheck failed.")) + } + } +} + +/// Application info that is kept locally. +/// +/// WARNING: You SHOULD NOT use `Self::Default` in production, as this will set the seed to +/// zero, which is insecure and might get in conflict with other accounts (similarly set up) +#[derive(Clone, Eq, PartialEq, Debug, Default, Deserialize, Serialize)] +pub struct AppState { + pub account: ShielderAccount, + pub node_rpc_url: String, + pub contract_address: Address, + pub relayer_rpc_url: RelayerRpcUrl, + pub relayer_address: Address, + pub signing_key: String, +} + +impl AppState { + /// Create a new `AppState` with a given signing key, which will be used for both signing + /// on-chain transactions and as a shielded account seed. + /// + /// Note: You SHOULD prefer using `Self::new` instead of `Default::default()`, unless you are + /// writing single-actor tests. + pub fn new(signing_key: &str) -> Self { + let seed = U256::from_str(signing_key).expect("Invalid key format - cannot cast to U256"); + Self { + account: ShielderAccount::new(seed), + signing_key: signing_key.into(), + ..Default::default() + } + } + + pub fn display_app_config(&self) -> String { + format!( + " +Node address: {} +Contract address: {} +Relayer url: {} +Relayer address: {} +Depositor signing key: {}", + self.node_rpc_url, + self.contract_address, + self.relayer_rpc_url.relay_url(), + self.relayer_address, + self.signing_key + ) + } + + pub fn create_shielder_user(&self) -> ShielderUser { + let signer = PrivateKeySigner::from_str(&self.signing_key) + .expect("Invalid key format - cannot cast to PrivateKeySigner"); + ShielderUser::new( + self.contract_address, + ConnectionPolicy::OnDemand { + rpc_url: self.node_rpc_url.clone(), + signer, + }, + ) + } + + pub async fn create_simple_provider(&self) -> Result { + create_simple_provider(&self.node_rpc_url).await + } +} diff --git a/crates/shielder-cli/src/config.rs b/crates/shielder-cli/src/config.rs new file mode 100644 index 00000000..037c04f1 --- /dev/null +++ b/crates/shielder-cli/src/config.rs @@ -0,0 +1,155 @@ +use std::path::PathBuf; + +use alloy_primitives::Address; +use anyhow::Result; +use clap::{Args, Parser, Subcommand, ValueEnum}; +use inquire::Password; + +#[derive(Clone, Eq, PartialEq, Debug, Parser)] +pub struct CliConfig { + /// Path to the file containing application state. + #[clap(long, default_value = "~/.shielder-state", value_parser = parsing::parse_path)] + pub state_file: PathBuf, + + /// Logging configuration. + #[clap(short = 'l', value_enum, default_value = "text")] + pub logging_format: LoggingFormat, + + /// Password for `state_file` encryption and decryption. + /// + /// If not provided, will be prompted. + #[clap(long)] + password: Option, + + /// Do not prompt for a password. Use empty password instead. Only for testing. + #[clap(long, default_value = "false")] + no_password: bool, + + #[clap(subcommand)] + pub command: Command, +} + +impl CliConfig { + pub fn password(&self) -> Result { + if self.no_password { + return Ok("".to_string()); + } + match &self.password { + Some(password) => Ok(password.clone()), + None => Ok(Password::new("Password (for encrypting local state):") + .without_confirmation() + .prompt()?), + } + } +} + +#[derive(Clone, Eq, PartialEq, Debug, Subcommand)] +pub enum Command { + #[clap(flatten)] + StateWrite(StateWriteCommand), + #[clap(flatten)] + StateRead(StateReadCommand), + #[clap(flatten)] + ContractInteraction(ContractInteractionCommand), +} + +#[derive(Clone, Eq, PartialEq, Debug, Subcommand)] +pub enum StateWriteCommand { + /// Initialize local state using ETH private key for both signing on-chain transactions and + /// as the shielded account seed. + Initialize { + /// Private key of the depositor account. + private_key: String, + }, + /// Set RPC address of the node that we will be connecting to. + NodeUrl { + /// RPC endpoint address of the node to connect to. + node: String, + }, + /// Set address of the Shielder contract. + ContractAddress { + /// Address of the Shielder contract. + address: Address, + }, + /// Set relayer URL address. + RelayerUrl { + /// Address of the relayer. + url: String, + }, + /// Set relayer chain address. + RelayerAddress { + /// Address of the relayer. + address: Address, + }, + /// Recover state from the blockchain. + RecoverState, +} + +#[derive(Clone, Eq, PartialEq, Debug, Subcommand)] +pub enum StateReadCommand { + /// Display account details. + DisplayAccount, + /// Display full account history. + History, + /// Display application configuration. + AppConfig, +} + +#[derive(Clone, Eq, PartialEq, Debug, Subcommand)] +pub enum ContractInteractionCommand { + /// Create new shielder account. + NewAccount(NewAccountCmd), + /// Shield some tokens. + Deposit(DepositCmd), + /// Unshield some tokens. + Withdraw(WithdrawCmd), +} + +#[derive(Clone, Eq, PartialEq, Debug, Args)] +pub struct NewAccountCmd { + /// Amount of the token to be shielded. + pub amount: u128, +} + +#[derive(Clone, Eq, PartialEq, Debug, Args)] +pub struct DepositCmd { + /// Amount of the token to be shielded. + pub amount: u128, +} + +#[derive(Clone, Eq, PartialEq, Debug, Args)] +pub struct WithdrawCmd { + /// Amount of the token to be shielded. + pub amount: u128, + /// Address to which the tokens should be sent. + pub to: Address, +} + +#[derive(Copy, Clone, Eq, PartialEq, Debug, Default, ValueEnum)] +pub enum LoggingFormat { + #[default] + Text, + Json, +} + +mod parsing { + use std::{path::PathBuf, str::FromStr}; + + use anyhow::{anyhow, Result}; + + pub fn parse_path(path: &str) -> Result { + let expanded_path = + shellexpand::full(path).map_err(|e| anyhow!("Failed to expand path: {e:?}"))?; + PathBuf::from_str(expanded_path.as_ref()) + .map_err(|e| anyhow!("Failed to interpret path: {e:?}")) + } +} + +#[cfg(test)] +mod tests { + #[test] + fn verify_cli() { + use clap::CommandFactory; + crate::config::CliConfig::command().debug_assert() + } +} diff --git a/crates/shielder-cli/src/main.rs b/crates/shielder-cli/src/main.rs new file mode 100644 index 00000000..b82a5a6d --- /dev/null +++ b/crates/shielder-cli/src/main.rs @@ -0,0 +1,139 @@ +use std::{env, io}; + +use anyhow::{anyhow, Result}; +use clap::Parser; +use tracing::info; +use tracing_subscriber::EnvFilter; + +use crate::{ + app_state::{AppState, RelayerRpcUrl}, + config::{ + CliConfig, + Command::{ContractInteraction, StateRead, StateWrite}, + ContractInteractionCommand, DepositCmd, LoggingFormat, NewAccountCmd, StateReadCommand, + StateWriteCommand, WithdrawCmd, + }, + recovery::recover_state, + shielder_ops::{deposit, new_account, withdraw}, + state_file::{create_and_save_new_state, get_app_state, save_app_state}, +}; + +mod app_state; +mod config; +mod recovery; +mod shielder_ops; +mod state_file; + +fn init_logging(format: LoggingFormat) -> Result<()> { + const LOG_CONFIGURATION_ENVVAR: &str = "RUST_LOG"; + + let filter = EnvFilter::new( + env::var(LOG_CONFIGURATION_ENVVAR) + .as_deref() + .unwrap_or("debug"), + ); + + let subscriber = tracing_subscriber::fmt() + .with_writer(io::stdout) + .with_target(true) + .with_env_filter(filter); + + match format { + LoggingFormat::Json => subscriber.json().try_init(), + LoggingFormat::Text => subscriber.try_init(), + } + .map_err(|err| anyhow!(err)) +} + +async fn perform_state_write_action( + app_state: &mut AppState, + command: StateWriteCommand, +) -> Result<()> { + match command { + StateWriteCommand::Initialize { .. } => { + unreachable!("State initialization should have been handled in a different context") + } + StateWriteCommand::NodeUrl { node } => { + info!("Setting node address to {node}"); + app_state.node_rpc_url = node; + } + StateWriteCommand::ContractAddress { address } => { + info!("Setting contract address to {address}"); + app_state.contract_address = address; + } + StateWriteCommand::RelayerUrl { url } => { + let relayer_rpc_url = RelayerRpcUrl::new(url.clone()); + relayer_rpc_url.check_connection().await?; + info!("Setting relayer url to {url}"); + app_state.relayer_rpc_url = relayer_rpc_url; + } + StateWriteCommand::RelayerAddress { address } => { + info!("Setting relayer address to {address}"); + app_state.relayer_address = address; + } + StateWriteCommand::RecoverState => { + recover_state(app_state).await?; + } + }; + Ok(()) +} + +fn perform_state_read_action(app_state: &AppState, command: StateReadCommand) -> Result<()> { + match command { + StateReadCommand::DisplayAccount => { + println!("{}", app_state.account) + } + StateReadCommand::History => { + println!("{:#?}", app_state.account.history) + } + StateReadCommand::AppConfig => { + println!("{}", app_state.display_app_config()) + } + }; + Ok(()) +} + +async fn perform_contract_action( + app_state: &mut AppState, + command: ContractInteractionCommand, +) -> Result<()> { + match command { + ContractInteractionCommand::Deposit(DepositCmd { amount }) => { + deposit(app_state, amount).await + } + ContractInteractionCommand::Withdraw(WithdrawCmd { amount, to }) => { + withdraw(app_state, amount, to).await + } + ContractInteractionCommand::NewAccount(NewAccountCmd { amount }) => { + new_account(app_state, amount).await + } + } +} + +#[tokio::main] +async fn main() -> Result<(), Box> { + let cli_config = CliConfig::parse(); + init_logging(cli_config.logging_format)?; + + let password = cli_config.password()?; + + if let StateWrite(StateWriteCommand::Initialize { private_key }) = cli_config.command { + create_and_save_new_state(&cli_config.state_file, &password, &private_key)?; + } else { + let mut app_state = get_app_state(&cli_config.state_file, &password)?; + + match cli_config.command { + StateWrite(cmd) => { + perform_state_write_action(&mut app_state, cmd).await?; + save_app_state(&app_state, &cli_config.state_file, &password)?; + } + StateRead(cmd) => perform_state_read_action(&app_state, cmd)?, + ContractInteraction(cmd) => { + perform_contract_action(&mut app_state, cmd).await?; + save_app_state(&app_state, &cli_config.state_file, &password)?; + } + } + } + + Ok(()) +} diff --git a/crates/shielder-cli/src/recovery.rs b/crates/shielder-cli/src/recovery.rs new file mode 100644 index 00000000..bc01409f --- /dev/null +++ b/crates/shielder-cli/src/recovery.rs @@ -0,0 +1,129 @@ +use alloy_eips::BlockNumberOrTag; +use alloy_primitives::{BlockHash, BlockNumber, U256}; +use alloy_provider::Provider; +use alloy_rpc_types_eth::Transaction; +use alloy_sol_types::SolCall; +use anyhow::{anyhow, bail, Result}; +use shielder_circuits::{utils::padded_hash, F}; +use shielder_rust_sdk::{ + account::{ShielderAccount, ShielderAction}, + contract::{ + call_type::DryRun, + events::get_event, + providers::create_simple_provider, + ShielderContract::{ + depositNativeCall, newAccountNativeCall, withdrawNativeCall, DepositNative, + NewAccountNative, ShielderContractEvents, WithdrawNative, + }, + }, + conversion::{field_to_u256, u256_to_field}, +}; +use tracing::{error, info}; + +use crate::app_state::AppState; + +pub async fn recover_state(app_state: &mut AppState) -> Result<()> { + let shielder_user = app_state.create_shielder_user(); + let AppState { + account, + node_rpc_url, + .. + } = app_state; + + let mut recovering_account = account.clone(); + + let provider = create_simple_provider(node_rpc_url).await?; + + loop { + info!("Recovering state for nonce {}", recovering_account.nonce); + + // Calculate the expected nullifier hash + let expected_nullifier = recovering_account.previous_nullifier(); + let expected_nullifier_hash = + field_to_u256(padded_hash::(&[u256_to_field(expected_nullifier)])); + + // Check if the nullifier hash has already been registered in the contract. + let mut block_number = shielder_user + .nullifiers::(expected_nullifier_hash) + .await?; + if block_number == U256::ZERO { + info!("Nullifier hash {expected_nullifier_hash} not found, recovering state completed"); + break; + }; + block_number -= U256::from(1); // remove the offset for null detection + if block_number >= U256::from(BlockNumber::MAX) { + let msg = format!("Block number too large: {block_number}"); + error!(msg); + bail!(msg); + } + let block_number = block_number.into_limbs()[0]; + info!("Nullifier hash {expected_nullifier_hash} found in block {block_number}"); + + // If yes, find the corresponding transaction. + let action = + find_shielder_transaction(&provider, block_number, &recovering_account).await?; + + // Apply the action to the account. + recovering_account.register_action(action); + } + + *account = recovering_account; + + Ok(()) +} + +async fn find_shielder_transaction( + provider: &impl Provider, + block_number: BlockNumber, + account: &ShielderAccount, +) -> Result { + let block = provider + .get_block_by_number(BlockNumberOrTag::Number(block_number), true) + .await? + .ok_or(anyhow!("Block not found"))?; + let txs = block + .transactions + .as_transactions() + .expect("We should get full transactions"); + + for tx in txs { + let Some(event) = try_get_shielder_event_for_tx(provider, tx, block.header.hash).await? + else { + continue; + }; + let event_note = event.note(); + let action = ShielderAction::from((tx.hash, event)); + + let mut hypothetical_account = account.clone(); + hypothetical_account.register_action(action.clone()); + let expected_note = hypothetical_account + .note() + .expect("We have just made an action"); + + if expected_note == event_note { + return Ok(action); + } + } + bail!("No matching Shielder transaction found in block {block_number}") +} + +async fn try_get_shielder_event_for_tx( + provider: &impl Provider, + tx: &Transaction, + block_hash: BlockHash, +) -> Result> { + let tx_data = tx.input.as_ref(); + let maybe_action = if newAccountNativeCall::abi_decode(tx_data, true).is_ok() { + let event = get_event::(provider, tx.hash, block_hash).await?; + Some(ShielderContractEvents::NewAccountNative(event)) + } else if depositNativeCall::abi_decode(tx_data, true).is_ok() { + let event = get_event::(provider, tx.hash, block_hash).await?; + Some(ShielderContractEvents::DepositNative(event)) + } else if withdrawNativeCall::abi_decode(tx_data, true).is_ok() { + let event = get_event::(provider, tx.hash, block_hash).await?; + Some(ShielderContractEvents::WithdrawNative(event)) + } else { + None + }; + Ok(maybe_action) +} diff --git a/crates/shielder-cli/src/shielder_ops/deposit.rs b/crates/shielder-cli/src/shielder_ops/deposit.rs new file mode 100644 index 00000000..3c1efc14 --- /dev/null +++ b/crates/shielder-cli/src/shielder_ops/deposit.rs @@ -0,0 +1,59 @@ +use alloy_primitives::U256; +use anyhow::Result; +use shielder_rust_sdk::{ + account::{ + call_data::{DepositCallType, MerkleProof}, + ShielderAction, + }, + contract::{ + call_type::Call, events::get_event, merkle_path::get_current_merkle_path, + ShielderContract::DepositNative, + }, +}; +use tracing::{debug, info}; + +use crate::{ + app_state::AppState, + shielder_ops::pk::{get_proving_equipment, CircuitType}, +}; + +pub async fn deposit(app_state: &mut AppState, amount: u128) -> Result<()> { + let amount = U256::from(amount); + let (params, pk) = get_proving_equipment(CircuitType::Deposit)?; + let leaf_index = app_state + .account + .current_leaf_index() + .expect("Deposit mustn't be the first action"); + let shielder_user = app_state.create_shielder_user(); + let (merkle_root, merkle_path) = get_current_merkle_path(leaf_index, &shielder_user).await?; + let (tx_hash, block_hash) = shielder_user + .deposit_native::( + app_state.account.prepare_call::( + ¶ms, + &pk, + amount, + &MerkleProof { + root: merkle_root, + path: merkle_path, + }, + ), + amount, + ) + .await?; + + let deposit_event = get_event::( + &app_state.create_simple_provider().await?, + tx_hash, + block_hash, + ) + .await?; + debug!("Deposit event: {deposit_event:?}"); + + app_state.account.register_action(ShielderAction::deposit( + amount, + deposit_event.newNoteIndex, + tx_hash, + )); + info!("Deposited {amount} tokens"); + Ok(()) +} diff --git a/crates/shielder-cli/src/shielder_ops/mod.rs b/crates/shielder-cli/src/shielder_ops/mod.rs new file mode 100644 index 00000000..717f7914 --- /dev/null +++ b/crates/shielder-cli/src/shielder_ops/mod.rs @@ -0,0 +1,8 @@ +pub use deposit::deposit; +pub use new_account::new_account; +pub use withdraw::withdraw; + +mod deposit; +mod new_account; +mod pk; +mod withdraw; diff --git a/crates/shielder-cli/src/shielder_ops/new_account.rs b/crates/shielder-cli/src/shielder_ops/new_account.rs new file mode 100644 index 00000000..83d1493d --- /dev/null +++ b/crates/shielder-cli/src/shielder_ops/new_account.rs @@ -0,0 +1,44 @@ +use alloy_primitives::U256; +use anyhow::Result; +use shielder_rust_sdk::{ + account::{call_data::NewAccountCallType, ShielderAction}, + contract::{call_type::Call, events::get_event, ShielderContract::NewAccountNative}, +}; +use tracing::{debug, info}; + +use crate::{ + app_state::AppState, + shielder_ops::pk::{get_proving_equipment, CircuitType}, +}; + +pub async fn new_account(app_state: &mut AppState, amount: u128) -> Result<()> { + let amount = U256::from(amount); + let (params, pk) = get_proving_equipment(CircuitType::NewAccount)?; + let (tx_hash, block_hash) = app_state + .create_shielder_user() + .create_new_account_native::( + app_state + .account + .prepare_call::(¶ms, &pk, amount, &()), + amount, + ) + .await?; + + let new_account_event = get_event::( + &app_state.create_simple_provider().await?, + tx_hash, + block_hash, + ) + .await?; + debug!("New account event: {new_account_event:?}"); + + app_state + .account + .register_action(ShielderAction::new_account( + amount, + new_account_event.newNoteIndex, + tx_hash, + )); + info!("Created new account with {amount} tokens"); + Ok(()) +} diff --git a/crates/shielder-cli/src/shielder_ops/pk.rs b/crates/shielder-cli/src/shielder_ops/pk.rs new file mode 100644 index 00000000..8944794a --- /dev/null +++ b/crates/shielder-cli/src/shielder_ops/pk.rs @@ -0,0 +1,146 @@ +use std::{fs, path::PathBuf, str::FromStr}; + +use anyhow::Result; +use shielder_circuits::{ + circuits::{Params, ProvingKey}, + consts::RANGE_PROOF_CHUNK_SIZE, + deposit::DepositCircuit, + generate_keys_with_min_k, + marshall::{marshall_params, marshall_pk, unmarshall_params, unmarshall_pk}, + new_account::NewAccountCircuit, + withdraw::WithdrawCircuit, + Params as _, F, MAX_K, +}; +use shielder_rust_sdk::powers_of_tau::{get_ptau_file_path, read as read_setup_parameters, Format}; +use tracing::debug; + +const NEW_ACCOUNT_PK_FILE: &str = "~/shielder-cli/new_account_pk"; +const DEPOSIT_PK_FILE: &str = "~/shielder-cli/deposit_pk"; +const WITHDRAW_PK_FILE: &str = "~/shielder-cli/withdraw_pk"; +const PROVING_PARAMS_FILE: &str = "~/shielder-cli/proving_params"; + +#[derive(Copy, Clone, Debug)] +pub enum CircuitType { + NewAccount, + Deposit, + Withdraw, +} + +impl CircuitType { + pub fn filepath(self) -> Result { + expand_path(match self { + CircuitType::NewAccount => NEW_ACCOUNT_PK_FILE, + CircuitType::Deposit => DEPOSIT_PK_FILE, + CircuitType::Withdraw => WITHDRAW_PK_FILE, + }) + } + + pub fn unmarshall_pk(self, bytes: &[u8]) -> Result<(u32, ProvingKey)> { + match self { + CircuitType::NewAccount => unmarshall_pk::>(bytes), + CircuitType::Deposit => { + unmarshall_pk::>(bytes) + } + CircuitType::Withdraw => { + unmarshall_pk::>(bytes) + } + } + .map_err(|_| anyhow::Error::msg("Failed to unmarshall proving key")) + } + + pub fn generate_keys(self, full_params: Params) -> Result<(Params, u32, ProvingKey)> { + let (params, k, pk, _) = match self { + CircuitType::NewAccount => { + generate_keys_with_min_k::>(full_params)? + } + CircuitType::Deposit => { + generate_keys_with_min_k::>(full_params)? + } + CircuitType::Withdraw => { + generate_keys_with_min_k::>(full_params)? + } + }; + debug!("Generated keys for {self:?} circuit with k={k}"); + Ok((params, k, pk)) + } +} + +pub fn get_proving_equipment(circuit_type: CircuitType) -> Result<(Params, ProvingKey)> { + let full_params = get_params()?; + get_equipment(circuit_type, full_params) +} + +fn get_params() -> Result { + let file = expand_path(PROVING_PARAMS_FILE)?; + + debug!("Getting proving params from {file:?}"); + + match fs::read(file.clone()).map(|bytes| unmarshall_params(&bytes)) { + Ok(Ok(full_params)) => { + debug!("Found and decoded proving params from {file:?}"); + Ok(full_params) + } + _ => { + debug!("Params not found or found corrupted, importing new ones..."); + + let params = read_setup_parameters( + get_ptau_file_path(MAX_K, Format::PerpetualPowersOfTau), + Format::PerpetualPowersOfTau, + )?; + debug!("Generated new proving params"); + + save_content( + file.clone(), + &marshall_params(¶ms) + .map_err(|_| anyhow::Error::msg("Failed to marshall params"))?, + )?; + debug!("Saved proving params to {file:?}"); + + Ok(params) + } + } +} + +fn get_equipment( + circuit_type: CircuitType, + mut full_params: Params, +) -> Result<(Params, ProvingKey)> { + let file = circuit_type.filepath()?; + debug!("Getting proving key from {file:?} for {circuit_type:?} circuit"); + + match fs::read(file.clone()).map(|bytes| circuit_type.unmarshall_pk(&bytes)) { + Ok(Ok((k, pk))) => { + debug!("Found and decoded proving key from {file:?}"); + let old_k = full_params.k(); + full_params.downsize(k); + debug!("Downsized proving params from {old_k} to {k}"); + Ok((full_params, pk)) + } + _ => { + debug!("Proving key not found or found corrupted, generating new one..."); + + let (params, k, pk) = circuit_type.generate_keys(full_params)?; + debug!("Generated new proving key"); + + save_content( + file.clone(), + &marshall_pk(k, &pk) + .map_err(|_| anyhow::Error::msg("Failed to marshall proving key"))?, + )?; + debug!("Saved proving key to {file:?}"); + + Ok((params, pk)) + } + } +} + +fn expand_path(path: &str) -> Result { + Ok(PathBuf::from_str(shellexpand::full(path)?.as_ref())?) +} + +fn save_content(path: PathBuf, content: &[u8]) -> Result<()> { + if let Some(parent) = path.parent() { + fs::create_dir_all(parent)?; + } + fs::write(path, content).map_err(Into::into) +} diff --git a/crates/shielder-cli/src/shielder_ops/withdraw.rs b/crates/shielder-cli/src/shielder_ops/withdraw.rs new file mode 100644 index 00000000..e230dc56 --- /dev/null +++ b/crates/shielder-cli/src/shielder_ops/withdraw.rs @@ -0,0 +1,114 @@ +use alloy_primitives::{Address, BlockHash, TxHash, U256}; +use alloy_provider::Provider; +use anyhow::{anyhow, bail, Result}; +use serde::Serialize; +use shielder_relayer::{relayer_fee, RelayQuery, RelayResponse}; +use shielder_rust_sdk::{ + account::{ + call_data::{MerkleProof, WithdrawCallType, WithdrawExtra}, + ShielderAction, + }, + contract::{ + events::get_event, merkle_path::get_current_merkle_path, ShielderContract::WithdrawNative, + }, + version::contract_version, +}; +use tokio::time::sleep; +use tracing::{debug, info}; + +use crate::{ + app_state::AppState, + shielder_ops::pk::{get_proving_equipment, CircuitType}, +}; + +pub async fn withdraw(app_state: &mut AppState, amount: u128, to: Address) -> Result<()> { + app_state.relayer_rpc_url.check_connection().await?; + let amount = U256::from(amount) + relayer_fee(); + + if amount > app_state.account.shielded_amount { + bail!("Not enough funds to withdraw"); + } + + let relayer_response = reqwest::Client::new() + .post(app_state.relayer_rpc_url.relay_url()) + .json(&prepare_relayer_query(app_state, amount, to).await?) + .send() + .await?; + + debug!("Relayer response: {relayer_response:?}"); + if !relayer_response.status().is_success() { + bail!( + "Relayer failed to process the request: {:?}", + relayer_response.status() + ); + } + let tx_hash = relayer_response.json::().await?.tx_hash; + + let provider = app_state.create_simple_provider().await?; + let block_hash = get_block_hash(&provider, tx_hash).await?; + + let withdraw_event = get_event::(&provider, tx_hash, block_hash).await?; + debug!("Withdraw event: {withdraw_event:?}"); + + app_state.account.register_action(ShielderAction::withdraw( + amount, + withdraw_event.newNoteIndex, + tx_hash, + to, + )); + info!("Withdrawn {amount} tokens"); + Ok(()) +} + +async fn get_block_hash(provider: &impl Provider, tx_hash: TxHash) -> Result { + for _ in 0..5 { + if let Some(receipt) = provider.get_transaction_receipt(tx_hash).await? { + if let Some(block_hash) = receipt.block_hash { + return Ok(block_hash); + } + return Err(anyhow!("Transaction not included in any block")); + } + sleep(std::time::Duration::from_secs(1)).await; + } + bail!("Couldn't fetch transaction receipt") +} + +async fn prepare_relayer_query( + app_state: &AppState, + amount: U256, + to: Address, +) -> Result { + let (params, pk) = get_proving_equipment(CircuitType::Withdraw)?; + let leaf_index = app_state + .account + .current_leaf_index() + .expect("Deposit mustn't be the first action"); + let (merkle_root, merkle_path) = + get_current_merkle_path(leaf_index, &app_state.create_shielder_user()).await?; + + let calldata = app_state.account.prepare_call::( + ¶ms, + &pk, + amount, + &WithdrawExtra { + merkle_proof: MerkleProof { + root: merkle_root, + path: merkle_path, + }, + to, + relayer_address: app_state.relayer_address, + relayer_fee: relayer_fee(), + contract_version: contract_version(), + }, + ); + + Ok(RelayQuery { + id_hiding: calldata.idHiding, + amount, + withdraw_address: to, + merkle_root, + nullifier_hash: calldata.oldNullifierHash, + new_note: calldata.newNote, + proof: calldata.proof, + }) +} diff --git a/crates/shielder-cli/src/state_file.rs b/crates/shielder-cli/src/state_file.rs new file mode 100644 index 00000000..84453abd --- /dev/null +++ b/crates/shielder-cli/src/state_file.rs @@ -0,0 +1,57 @@ +use std::{ + fs, + fs::File, + path::{Path, PathBuf}, +}; + +use anyhow::{anyhow, bail, Result}; +use content_encryption::{decrypt_to_string, encrypt}; +use tracing::debug; + +use crate::app_state::AppState; + +/// Try to get `AppState` from `path`. If `path` describes non-existing file, error will be +/// returned. +/// +/// `path` will be decrypted with `password`. +pub fn get_app_state(path: &PathBuf, password: &str) -> Result { + if path.exists() { + debug!("File with state was found. Reading the state from {path:?}."); + read_from(path, password) + } else { + bail!("File {path:?} with state not found."); + } +} + +/// Save `app_state` to `path`. +/// +/// `path` will be encrypted with `password`. +pub fn save_app_state(app_state: &AppState, path: &PathBuf, password: &str) -> Result<()> { + let serialized = + serde_json::to_string_pretty(app_state).map_err(|e| anyhow!("Failed to serialize: {e}"))?; + fs::write(path, encrypt(serialized.as_bytes(), password.as_bytes())?) + .map_err(|e| anyhow!("Failed to save application state: {e}")) +} + +/// Read `AppState` from `path` (decrypting the content with `password`). +fn read_from(path: &Path, password: &str) -> Result { + let file_content = fs::read(path).map_err(|e| anyhow!("Failed to read file content: {e}"))?; + let decrypted_content = decrypt_to_string(&file_content, password.as_bytes())?; + serde_json::from_str::(&decrypted_content) + .map_err(|e| anyhow!("Failed to deserialize application state: {e}")) +} + +/// Create a new `AppState`, save it to `path` and return it. +pub fn create_and_save_new_state( + path: &PathBuf, + password: &str, + private_key: &str, +) -> Result { + File::create(path).map_err(|e| anyhow!("Failed to create {path:?}: {e}"))?; + + let state = AppState::new(private_key); + save_app_state(&state, path, password) + .map_err(|e| anyhow!("Failed to save state to {path:?}: {e}"))?; + + Ok(state) +} diff --git a/crates/shielder-relayer/Cargo.toml b/crates/shielder-relayer/Cargo.toml new file mode 100644 index 00000000..aabf53dd --- /dev/null +++ b/crates/shielder-relayer/Cargo.toml @@ -0,0 +1,37 @@ +[package] +name = "shielder-relayer" +version = "0.1.0" +readme = "README.md" +description = "Trusted service for private withdrawals from the zkOS Shielder contract" + +edition.workspace = true +authors.workspace = true +homepage.workspace = true +license.workspace = true +categories.workspace = true +repository.workspace = true + +[dependencies] +alloy-provider = { workspace = true } +alloy-rpc-types = { workspace = true } +alloy-signer = { workspace = true } +alloy-signer-local = { workspace = true } +anyhow = { workspace = true, default-features = true } +async-channel = { workspace = true } +axum = { workspace = true } +clap = { workspace = true, features = ["derive"] } +metrics = { workspace = true } +metrics-exporter-prometheus = { workspace = true } +openssl = { version = "0.10.59", features = ["vendored"] } +serde = { workspace = true, features = ["derive"] } +serde_json = { workspace = true } +shielder-rust-sdk = { workspace = true, features = ["contract", "native_token"] } +tokio = { workspace = true, features = ["rt-multi-thread", "time"] } +tower-http = { workspace = true, features = ["cors"] } +tracing = { workspace = true } +tracing-subscriber = { workspace = true, features = ["fmt", "json", "env-filter"] } + +[dev-dependencies] +rand = { workspace = true } +reqwest = { workspace = true, features = ["json"] } +testcontainers = { workspace = true } diff --git a/crates/shielder-relayer/Makefile b/crates/shielder-relayer/Makefile new file mode 100644 index 00000000..0bae63ba --- /dev/null +++ b/crates/shielder-relayer/Makefile @@ -0,0 +1,49 @@ +SHELL := /bin/bash + +CARGO_FILES = ../../Cargo.toml ../../Cargo.lock Cargo.toml + +BUILD ?= client +DOCKER_USER = "$(id -u):$(id -g)" + +RELAYER_CONTAINER_NAME = shielder-relayer +RELAYER_DOCKER_IMAGE = shielder-relayer + +.PHONY: help +help: ## Displays this help + @awk 'BEGIN {FS = ":.*##"; printf "$(MAKEFILE_NAME)\nUsage:\n make \033[1;36m\033[0m\n\nTargets:\n"} /^[a-zA-Z0-9_-]+:.*?##/ { printf " \033[1;36m%-25s\033[0m %s\n", $$1, $$2 }' $(MAKEFILE_LIST) + +.PHONY: build +build: + @cargo build --release + +.PHONY: test +test: build-image ## Run tests + @./test.sh + +.PHONY: lint +lint: ## Run linter + @cargo clippy --release -- -D warnings + @cargo +nightly fmt --all + +.PHONY: build-image +build-image: ## Builds a Docker image with the Relayer service binary. Use BUILD=client to use a binary built on the client. +ifeq ($(BUILD),client) + @cargo build --release + @cd ../.. && docker build --tag "${RELAYER_DOCKER_IMAGE}" -f "crates/shielder-relayer/docker/Dockerfile.client" . +else ifeq ($(BUILD),docker) + @cd ../.. && DOCKER_BUILDKIT=1 docker build --ssh default --tag "${RELAYER_DOCKER_IMAGE}" -f "crates/shielder-relayer/docker/Dockerfile.docker" . +else + echo "Don't know what to do with ${BUILD}"; exit -1; +endif + +.PHONY: run +run: build-image stop ## Start the Relayer service in a local Docker container + @DOCKER_USER=$(DOCKER_USER) \ + RELAYER_CONTAINER_NAME=$(RELAYER_CONTAINER_NAME) \ + RELAYER_DOCKER_IMAGE=$(RELAYER_DOCKER_IMAGE) \ + ./run-relayer.sh + +.PHONY: stop +stop: + @docker kill "${RELAYER_CONTAINER_NAME}" 1> /dev/null 2>&1 || true + @docker rm "${RELAYER_CONTAINER_NAME}" 1> /dev/null 2>&1 || true diff --git a/crates/shielder-relayer/README.md b/crates/shielder-relayer/README.md new file mode 100644 index 00000000..16c28ca3 --- /dev/null +++ b/crates/shielder-relayer/README.md @@ -0,0 +1,84 @@ +# shielder-relayer + +This crate provides a relayer service for the Shielder system. +It implements concept described in https://docs.alephzero.org/aleph-zero/protocol-details/shielder/relayers. + +# Usage + +## Running the relayer natively + +You can run the relayer just like any other Rust binary with `cargo run --release`. + +```shell +Configuration for the Shielder relayer through the command line arguments. + +All fields are optional, as they can be provided either through environment variables or, in some cases, through default values. + +Usage: shielder-relayer [OPTIONS] + +Options: + --logging-format + Logging format configuration. If not provided, the value from the environment variable `LOGGING_FORMAT` will be used. If that is not set, the default value is `Text`. + + [possible values: text, json] + + --host + Host where the server should be run. If not provided, the value from the environment variable `RELAYER_HOST` will be used. If that is not set, the default value is `0.0.0.0`. + + --port + Port where the server should be run. If not provided, the value from the environment variable `RELAYER_PORT` will be used. If that is not set, the default value is `4141`. + + --metrics-port + Port where the server metrics should be exposed. If not provided, the value from the environment variable `RELAYER_METRICS_PORT` will be used. If that is not set, the default value is `9615`. + + --node-rpc-url + URL of the Ethereum RPC node. If not provided, the value from the environment variable `NODE_RPC_URL` will be used. + + --shielder-contract-address + Address of the Shielder contract. If not provided, the value from the environment variable `SHIELDER_CONTRACT_ADDRESS` will be used. + + --relayer-address + Address of the relayer. If not provided, the value from the environment variable `RELAYER_ADDRESS` will be used. + + --signing-key + Signing key of the relayer. If not provided, the value from the environment variable `RELAYER_SIGNING_KEY` will be used. + + -h, --help + Print help (see a summary with '-h') +``` + +## Running the relayer in Docker + +You can also run the relayer in a Docker container. + +```shell +RELAYER_PORT=4141 \ +NODE_RPC_URL=http://localhost:8545 \ +RELAYER_ADDRESS=0xCacA011152e011634cFC7f663998af44BC55FF4c \ +RELAYER_SIGNING_KEY=0x547a81fc1782a6f29613dd15fe0f97321379875fe5a99e2a9d8258b4d51ac660 \ +SHIELDER_CONTRACT_ADDRESS=0xCaCa0634D1CEF7BD98c07e65C14Dd1B619906dD4 \ +make run && \ +docker logs shielder-relayer --follow +``` + +This will run a Docker container `shielder-relayer` with the service available on `RELAYER_PORT` (default: 4141). +You can stop the service with `make stop`. + +# API + +Apart from operational / monitoring endpoints, the relayer provides the following API: + +## `POST /relay` + +Submits a new withdrawal transaction to the Shielder contract through the relayer. +It expects one json object in the body, compliant with the structure: +```rust +pub struct RelayQuery { + pub amount: U256, + pub withdraw_address: Address, + pub merkle_root: U256, + pub nullifier_hash: U256, + pub new_note: U256, + pub proof: Bytes, +} +``` diff --git a/crates/shielder-relayer/docker/Dockerfile.client b/crates/shielder-relayer/docker/Dockerfile.client new file mode 100644 index 00000000..c4b7ff00 --- /dev/null +++ b/crates/shielder-relayer/docker/Dockerfile.client @@ -0,0 +1,15 @@ +FROM debian:bookworm-slim + +RUN apt-get update && \ + apt-get install -y \ + libssl-dev \ + ca-certificates && \ + rm -rf /tmp/* /var/{tmp,cache}/* /var/lib/{apt,dpkg}/ + +COPY ./target/release/shielder-relayer /usr/local/bin +RUN chmod +x /usr/local/bin/shielder-relayer + +RUN useradd server +USER server + +ENTRYPOINT ["shielder-relayer"] diff --git a/crates/shielder-relayer/docker/Dockerfile.docker b/crates/shielder-relayer/docker/Dockerfile.docker new file mode 100644 index 00000000..bfceddd3 --- /dev/null +++ b/crates/shielder-relayer/docker/Dockerfile.docker @@ -0,0 +1,42 @@ +# syntax=docker/dockerfile:experimental + +FROM debian:bookworm-slim AS build + +RUN apt-get update && \ + apt-get install -y \ + curl \ + libssl-dev \ + ca-certificates \ + build-essential \ + pkg-config \ + openssh-client && \ + rm -rf /tmp/* /var/{tmp,cache}/* /var/lib/{apt,dpkg}/ + +RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain none +ENV PATH="/root/.cargo/bin:${PATH}" + +COPY ./crates ./zkos/crates +COPY ./Cargo.toml ./zkos/Cargo.toml +COPY ./Cargo.lock ./zkos/Cargo.lock +COPY ./rust-toolchain.toml ./zkos/rust-toolchain.toml + +# download public key for github.com +RUN mkdir -p -m 0600 ~/.ssh && ssh-keyscan github.com >> ~/.ssh/known_hosts + +RUN --mount=type=ssh cd zkos && cargo build --release -p shielder-relayer + +FROM debian:bookworm-slim + +RUN apt-get update && \ + apt-get install -y \ + libssl-dev \ + ca-certificates && \ + rm -rf /tmp/* /var/{tmp,cache}/* /var/lib/{apt,dpkg}/ + +COPY --from=build /zkos/target/release/shielder-relayer /usr/local/bin +RUN chmod +x /usr/local/bin/shielder-relayer + +RUN useradd server +USER server + +ENTRYPOINT ["shielder-relayer"] diff --git a/crates/shielder-relayer/docker/Dockerfile.dockerignore b/crates/shielder-relayer/docker/Dockerfile.dockerignore new file mode 100644 index 00000000..5c5046d3 --- /dev/null +++ b/crates/shielder-relayer/docker/Dockerfile.dockerignore @@ -0,0 +1,3 @@ +crates/shielder-relayer/Makefile +crates/shielder-relayer/test.sh +crates/shielder-relayer/run-relayer.sh \ No newline at end of file diff --git a/crates/shielder-relayer/run-relayer.sh b/crates/shielder-relayer/run-relayer.sh new file mode 100755 index 00000000..af1d160c --- /dev/null +++ b/crates/shielder-relayer/run-relayer.sh @@ -0,0 +1,69 @@ +#!/usr/bin/env bash + +# NOTE: You should use `run` target from `Makefile` instead of this script. + +set -u + +# The following environment variables are required to run the Relayer service. Other configuration parameters +# have their default fallback values. +REQUIRED_RUN_VARS=( + "NODE_RPC_URL" + "FEE_DESTINATION_KEY" + "RELAYER_SIGNING_KEYS" + "SHIELDER_CONTRACT_ADDRESS" + "RELAYER_DOCKER_IMAGE" + "RELAYER_CONTAINER_NAME" + "DOCKER_USER" +) + +for var in "${REQUIRED_RUN_VARS[@]}"; do + if [ -z "${var}" ]; then + echo "Error: Environment variable $var is not set." + exit 1 + fi +done + +ARGS=( + -u "${DOCKER_USER}" + --name="${RELAYER_CONTAINER_NAME}" + -e RUST_LOG=info +) + +# Add network args based on OS +if [[ "$OSTYPE" == "darwin"* ]]; then + # macOS + ARGS+=(-p "${RELAYER_PORT}:${RELAYER_PORT}") +else + # Linux + ARGS+=(--network host) +fi + +if [[ -n "${RELAYER_PORT:-}" ]]; then + ARGS+=(-e RELAYER_PORT=${RELAYER_PORT}) +fi +if [[ -n "${NODE_RPC_URL:-}" ]]; then + ARGS+=(-e NODE_RPC_URL=${NODE_RPC_URL}) +fi +if [[ -n "${FEE_DESTINATION_KEY:-}" ]]; then + ARGS+=(-e FEE_DESTINATION_KEY=${FEE_DESTINATION_KEY}) +fi +if [[ -n "${RELAYER_SIGNING_KEYS:-}" ]]; then + ARGS+=(-e RELAYER_SIGNING_KEYS=${RELAYER_SIGNING_KEYS}) +fi +if [[ -n "${SHIELDER_CONTRACT_ADDRESS:-}" ]]; then + ARGS+=(-e SHIELDER_CONTRACT_ADDRESS=${SHIELDER_CONTRACT_ADDRESS}) +fi +if [[ -n "${DRY_RUNNING:-}" ]]; then + ARGS+=(-e DRY_RUNNING=${DRY_RUNNING}) +fi +if [[ -n "${NONCE_POLICY:-}" ]]; then + ARGS+=(-e NONCE_POLICY=${NONCE_POLICY}) +fi +if [[ -n "${RELAY_COUNT_FOR_RECHARGE:-}" ]]; then + ARGS+=(-e RELAY_COUNT_FOR_RECHARGE=${RELAY_COUNT_FOR_RECHARGE}) +fi +if [[ -n "${BALANCE_MONITOR_INTERVAL_SECS:-}" ]]; then + ARGS+=(-e BALANCE_MONITOR_INTERVAL_SECS=${BALANCE_MONITOR_INTERVAL_SECS}) +fi + +docker run --rm -d "${ARGS[@]}" "${RELAYER_DOCKER_IMAGE}" diff --git a/crates/shielder-relayer/src/config/cli.rs b/crates/shielder-relayer/src/config/cli.rs new file mode 100644 index 00000000..e9ac0694 --- /dev/null +++ b/crates/shielder-relayer/src/config/cli.rs @@ -0,0 +1,124 @@ +use clap::Parser; +use shielder_relayer::*; + +use crate::config::{ + defaults::*, + enums::{DryRunning, LoggingFormat, NoncePolicy}, +}; + +/// Configuration for the Shielder relayer through the command line arguments. +/// +/// All fields are optional, as they can be provided either through environment variables or, +/// in some cases, through default values. +#[derive(Clone, Debug, Parser)] +pub struct CLIConfig { + #[clap( + long, + value_enum, + help = "Logging format configuration.", + long_help = format!("Logging format configuration. If not provided, the value from the \ + environment variable `{LOGGING_FORMAT_ENV}` will be used. If that is not set, the \ + default value is `{DEFAULT_LOGGING_FORMAT:?}`.") + )] + pub logging_format: Option, + + #[clap( + long, + help = "Host where the server should be run.", + long_help = format!("Host where the server should be run. If not provided, the value from the \ + environment variable `{RELAYER_HOST_ENV}` will be used. If that is not set, the \ + default value is `{DEFAULT_HOST}`.") + )] + pub host: Option, + + #[clap( + long, + help = "Port where the server should be run.", + long_help = format!("Port where the server should be run. If not provided, the value from the \ + environment variable `{RELAYER_PORT_ENV}` will be used. If that is not set, the \ + default value is `{DEFAULT_PORT}`.") + )] + pub port: Option, + + #[clap( + long, + help = "Port where the server metrics should be exposed.", + long_help = format!("Port where the server metrics should be exposed. If not provided, the \ + value from the environment variable `{RELAYER_METRICS_PORT_ENV}` will be used. If that \ + is not set, the default value is `{DEFAULT_METRICS_PORT}`.") + )] + pub metrics_port: Option, + + #[clap( + long, + help = "Interval (in seconds) for monitoring signers' balances.", + long_help = format!("Interval (in seconds) for monitoring signers' balances. If not \ + provided, the value from the environment variable `{BALANCE_MONITOR_INTERVAL_SECS_ENV}` \ + will be used. If that is not set, the default value is \ + `{DEFAULT_BALANCE_MONITOR_INTERVAL_SECS}`.") + )] + pub balance_monitor_interval_secs: Option, + + #[clap( + long, + help = "URL of the Ethereum RPC node.", + long_help = format!("URL of the Ethereum RPC node. If not provided, the value from the \ + environment variable `{NODE_RPC_URL_ENV}` will be used.") + )] + pub node_rpc_url: Option, + + #[clap( + long, + help = "Address of the Shielder contract.", + long_help = format!("Address of the Shielder contract. If not provided, the value from the \ + environment variable `{SHIELDER_CONTRACT_ADDRESS_ENV}` will be used.") + )] + pub shielder_contract_address: Option, + + #[clap( + long, + help = "Fee destination signing key.", + long_help = format!("Signing key of the address where the fees should go. If not provided, \ + the value from the environment variable `{FEE_DESTINATION_KEY_ENV}` will be used.") + )] + pub fee_destination_key: Option, + + #[clap( + long, + help = "Signing keys of the relayer.", + long_help = format!("Signing keys of the relayer. If not provided, the value from the \ + environment variable `{RELAYER_SIGNING_KEYS_ENV}` will be used."), + num_args = 1.. + )] + pub signing_keys: Option>, + + #[clap( + long, + value_enum, + help = "Nonce management policy.", + long_help = format!("Nonce management policy. If not provided, the value from the \ + environment variable `{NONCE_POLICY_ENV}` will be used. If that is not set, the \ + default value is `{DEFAULT_NONCE_POLICY:?}`.") + )] + pub nonce_policy: Option, + + #[clap( + long, + value_enum, + help = "Dry running policy.", + long_help = format!("Dry running policy. If not provided, the value from the \ + environment variable `{DRY_RUNNING_ENV}` will be used. If that is not set, the \ + default value is `{DEFAULT_DRY_RUNNING:?}`.") + )] + pub dry_running: Option, + + #[clap( + long, + value_enum, + help = "How many relays must a single relayer do to get a recharge.", + long_help = format!("Relay count for recharge. If not provided, the value from the \ + environment variable `{RELAY_COUNT_FOR_RECHARGE_ENV}` will be used. If that is not set,\ + the default value is `{DEFAULT_RELAY_COUNT_FOR_RECHARGE:?}`.") + )] + pub relay_count_for_recharge: Option, +} diff --git a/crates/shielder-relayer/src/config/defaults.rs b/crates/shielder-relayer/src/config/defaults.rs new file mode 100644 index 00000000..1513babd --- /dev/null +++ b/crates/shielder-relayer/src/config/defaults.rs @@ -0,0 +1,10 @@ +use crate::config::{enums::DryRunning, LoggingFormat, NoncePolicy}; + +pub const DEFAULT_LOGGING_FORMAT: LoggingFormat = LoggingFormat::Text; +pub const DEFAULT_HOST: &str = "0.0.0.0"; +pub const DEFAULT_PORT: u16 = 4141; +pub const DEFAULT_METRICS_PORT: u16 = 9615; +pub const DEFAULT_BALANCE_MONITOR_INTERVAL_SECS: u64 = 60 * 15; +pub const DEFAULT_NONCE_POLICY: NoncePolicy = NoncePolicy::Caching; +pub const DEFAULT_DRY_RUNNING: DryRunning = DryRunning::Always; +pub const DEFAULT_RELAY_COUNT_FOR_RECHARGE: u32 = 20; diff --git a/crates/shielder-relayer/src/config/enums.rs b/crates/shielder-relayer/src/config/enums.rs new file mode 100644 index 00000000..c5f557e1 --- /dev/null +++ b/crates/shielder-relayer/src/config/enums.rs @@ -0,0 +1,60 @@ +use std::str::FromStr; + +use clap::ValueEnum; + +#[derive(Copy, Clone, Eq, PartialEq, Debug, Default, ValueEnum)] +pub enum LoggingFormat { + #[default] + Text, + Json, +} + +impl FromStr for LoggingFormat { + type Err = (); + + fn from_str(s: &str) -> Result { + match s.to_lowercase().as_str() { + "text" => Ok(Self::Text), + "json" => Ok(Self::Json), + _ => Err(()), + } + } +} + +#[derive(Copy, Clone, Eq, PartialEq, Debug, Default, ValueEnum)] +pub enum NoncePolicy { + #[default] + Caching, + Stateless, +} + +impl FromStr for NoncePolicy { + type Err = (); + + fn from_str(s: &str) -> Result { + match s.to_lowercase().as_str() { + "caching" => Ok(Self::Caching), + "stateless" => Ok(Self::Stateless), + _ => Err(()), + } + } +} + +#[derive(Copy, Clone, Eq, PartialEq, Debug, Default, ValueEnum)] +pub enum DryRunning { + #[default] + Always, + Optimistic, +} + +impl FromStr for DryRunning { + type Err = (); + + fn from_str(s: &str) -> Result { + match s.to_lowercase().as_str() { + "always" => Ok(Self::Always), + "optimistic" => Ok(Self::Optimistic), + _ => Err(()), + } + } +} diff --git a/crates/shielder-relayer/src/config/mod.rs b/crates/shielder-relayer/src/config/mod.rs new file mode 100644 index 00000000..2f13c529 --- /dev/null +++ b/crates/shielder-relayer/src/config/mod.rs @@ -0,0 +1,163 @@ +use std::str::FromStr; + +use clap::Parser; +use cli::CLIConfig; +use defaults::{ + DEFAULT_DRY_RUNNING, DEFAULT_HOST, DEFAULT_LOGGING_FORMAT, DEFAULT_METRICS_PORT, + DEFAULT_NONCE_POLICY, DEFAULT_PORT, +}; +pub use enums::{DryRunning, LoggingFormat, NoncePolicy}; +use shielder_relayer::{ + BALANCE_MONITOR_INTERVAL_SECS_ENV, DRY_RUNNING_ENV, FEE_DESTINATION_KEY_ENV, + LOGGING_FORMAT_ENV, NODE_RPC_URL_ENV, NONCE_POLICY_ENV, RELAYER_HOST_ENV, + RELAYER_METRICS_PORT_ENV, RELAYER_PORT_ENV, RELAYER_SIGNING_KEYS_ENV, + RELAY_COUNT_FOR_RECHARGE_ENV, SHIELDER_CONTRACT_ADDRESS_ENV, +}; +use shielder_rust_sdk::alloy_primitives::Address; + +use crate::config::defaults::{ + DEFAULT_BALANCE_MONITOR_INTERVAL_SECS, DEFAULT_RELAY_COUNT_FOR_RECHARGE, +}; + +mod cli; +mod defaults; +mod enums; +#[cfg(test)] +mod tests; + +#[derive(Clone, Eq, PartialEq, Debug)] +pub struct NetworkConfig { + pub host: String, + pub port: u16, + pub metrics_port: u16, +} + +impl NetworkConfig { + pub fn main_address(&self) -> String { + format!("{}:{}", self.host, self.port) + } + + pub fn metrics_address(&self) -> String { + format!("{}:{}", self.host, self.metrics_port) + } +} + +#[derive(Clone, Eq, PartialEq, Debug)] +pub struct ChainConfig { + pub node_rpc_url: String, + pub shielder_contract_address: Address, + pub fee_destination_key: String, + pub signing_keys: Vec, +} + +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +pub struct OperationalConfig { + pub balance_monitor_interval_secs: u64, + pub nonce_policy: NoncePolicy, + pub dry_running: DryRunning, + pub relay_count_for_recharge: u32, +} + +/// Resolved configuration for the Shielder relayer. Order of precedence is: +/// 1. Command line arguments (`CLIConfig`). +/// 2. Environment variables. +/// 3. Default values (available only for some fields). +/// +/// For field documentation, see their counterparts in `CLIConfig`. +#[derive(Clone, Eq, PartialEq, Debug)] +pub struct ServerConfig { + pub logging_format: LoggingFormat, + pub network: NetworkConfig, + pub chain: ChainConfig, + pub operations: OperationalConfig, +} + +/// Resolves the configuration for the Shielder relayer using the command line arguments, +/// environment variables, and default values. +pub fn resolve_config() -> ServerConfig { + resolve_config_from_cli_config(CLIConfig::parse()) +} + +fn resolve_config_from_cli_config( + CLIConfig { + logging_format, + host, + port, + metrics_port, + balance_monitor_interval_secs, + node_rpc_url, + shielder_contract_address, + fee_destination_key, + signing_keys, + nonce_policy, + dry_running, + relay_count_for_recharge, + }: CLIConfig, +) -> ServerConfig { + let to_address = |s: &str| Address::from_str(s).expect("Invalid address"); + + let signing_keys = signing_keys.unwrap_or_else(|| { + std::env::var(RELAYER_SIGNING_KEYS_ENV) + .expect("Missing required configuration") + .split(',') + .map(|s| s.to_string()) + .collect() + }); + + let network_config = NetworkConfig { + host: resolve_value(host, RELAYER_HOST_ENV, Some(DEFAULT_HOST.to_string())), + port: resolve_value(port, RELAYER_PORT_ENV, Some(DEFAULT_PORT)), + metrics_port: resolve_value( + metrics_port, + RELAYER_METRICS_PORT_ENV, + Some(DEFAULT_METRICS_PORT), + ), + }; + + let chain_config = ChainConfig { + node_rpc_url: resolve_value(node_rpc_url, NODE_RPC_URL_ENV, None), + shielder_contract_address: to_address(&resolve_value( + shielder_contract_address, + SHIELDER_CONTRACT_ADDRESS_ENV, + None, + )), + fee_destination_key: resolve_value(fee_destination_key, FEE_DESTINATION_KEY_ENV, None), + signing_keys, + }; + + let operational_config = OperationalConfig { + balance_monitor_interval_secs: resolve_value( + balance_monitor_interval_secs, + BALANCE_MONITOR_INTERVAL_SECS_ENV, + Some(DEFAULT_BALANCE_MONITOR_INTERVAL_SECS), + ), + nonce_policy: resolve_value(nonce_policy, NONCE_POLICY_ENV, Some(DEFAULT_NONCE_POLICY)), + dry_running: resolve_value(dry_running, DRY_RUNNING_ENV, Some(DEFAULT_DRY_RUNNING)), + relay_count_for_recharge: resolve_value( + relay_count_for_recharge, + RELAY_COUNT_FOR_RECHARGE_ENV, + Some(DEFAULT_RELAY_COUNT_FOR_RECHARGE), + ), + }; + + ServerConfig { + logging_format: resolve_value( + logging_format, + LOGGING_FORMAT_ENV, + Some(DEFAULT_LOGGING_FORMAT), + ), + network: network_config, + chain: chain_config, + operations: operational_config, + } +} + +fn resolve_value(value: Option, env_var: &str, default: Option) -> T { + value.unwrap_or_else(|| { + std::env::var(env_var) + .ok() + .and_then(|v| T::from_str(&v).ok()) + .or(default) + .expect("Missing required configuration") + }) +} diff --git a/crates/shielder-relayer/src/config/tests.rs b/crates/shielder-relayer/src/config/tests.rs new file mode 100644 index 00000000..4da5aacd --- /dev/null +++ b/crates/shielder-relayer/src/config/tests.rs @@ -0,0 +1,80 @@ +use shielder_relayer::{RELAYER_PORT_ENV, RELAYER_SIGNING_KEYS_ENV}; +use shielder_rust_sdk::alloy_primitives::address; + +use super::*; + +#[test] +fn verify_cli() { + use clap::CommandFactory; + CLIConfig::command().debug_assert() +} + +#[test] +fn config_resolution() { + // ---- Target configuration. -------------------------------------------------------------- + let logging_format = LoggingFormat::Json; + let host = DEFAULT_HOST.to_string(); + let port = 1234; + let metrics_port = 5678; + let balance_monitor_interval_secs = 60; + let node_rpc_url = "http://localhost:8545".to_string(); + let shielder_contract_address = address!("0000000000000000000000000000000000000000"); + let fee_destination_key = "key0".to_string(); + let key1 = "key1".to_string(); + let key2 = "key2".to_string(); + let nonce_policy = DEFAULT_NONCE_POLICY; + let dry_running = DryRunning::Always; + let relay_count_for_recharge = DEFAULT_RELAY_COUNT_FOR_RECHARGE; + + let expected_config = ServerConfig { + logging_format, // from CLI + network: NetworkConfig { + host, // default + port, // from env + metrics_port, // from CLI + }, + chain: ChainConfig { + node_rpc_url: node_rpc_url.clone(), // from CLI + shielder_contract_address, // from CLI + fee_destination_key: fee_destination_key.clone(), // from env + signing_keys: vec![key1.clone(), key2.clone()], // from env + }, + operations: OperationalConfig { + balance_monitor_interval_secs, // from env + nonce_policy, // default + dry_running, // from CLI + relay_count_for_recharge, // default + }, + }; + + // ---- CLI configuration. ----------------------------------------------------------------- + let cli_config = CLIConfig { + logging_format: Some(logging_format), + host: None, + port: None, + metrics_port: Some(metrics_port), + balance_monitor_interval_secs: None, + node_rpc_url: Some(node_rpc_url), + shielder_contract_address: Some(shielder_contract_address.to_string()), + fee_destination_key: None, + signing_keys: None, + nonce_policy: None, + dry_running: Some(dry_running), + relay_count_for_recharge: None, + }; + + // ---- Environment variables. ----------------------------------------------------------- + unsafe { + std::env::set_var(RELAYER_PORT_ENV, port.to_string()); + std::env::set_var( + BALANCE_MONITOR_INTERVAL_SECS_ENV, + balance_monitor_interval_secs.to_string(), + ); + std::env::set_var(FEE_DESTINATION_KEY_ENV, fee_destination_key); + std::env::set_var(RELAYER_SIGNING_KEYS_ENV, format!("{key1},{key2}")); + } + + // ---- Test. ------------------------------------------------------------------------------ + let resolved_config = resolve_config_from_cli_config(cli_config); + assert_eq!(resolved_config, expected_config); +} diff --git a/crates/shielder-relayer/src/lib.rs b/crates/shielder-relayer/src/lib.rs new file mode 100644 index 00000000..f86ccff4 --- /dev/null +++ b/crates/shielder-relayer/src/lib.rs @@ -0,0 +1,60 @@ +use axum::Json; +use serde::{Deserialize, Serialize}; +use shielder_rust_sdk::{ + alloy_primitives::{Address, Bytes, TxHash, U256}, + native_token::ONE_TZERO, +}; + +pub const LOGGING_FORMAT_ENV: &str = "LOGGING_FORMAT"; +pub const RELAYER_HOST_ENV: &str = "RELAYER_HOST"; +pub const RELAYER_PORT_ENV: &str = "RELAYER_PORT"; +pub const RELAYER_METRICS_PORT_ENV: &str = "RELAYER_METRICS_PORT"; +pub const BALANCE_MONITOR_INTERVAL_SECS_ENV: &str = "BALANCE_MONITOR_INTERVAL_SECS"; +pub const FEE_DESTINATION_KEY_ENV: &str = "FEE_DESTINATION_KEY"; +pub const RELAYER_SIGNING_KEYS_ENV: &str = "RELAYER_SIGNING_KEYS"; +pub const NODE_RPC_URL_ENV: &str = "NODE_RPC_URL"; +pub const SHIELDER_CONTRACT_ADDRESS_ENV: &str = "SHIELDER_CONTRACT_ADDRESS"; +pub const NONCE_POLICY_ENV: &str = "NONCE_POLICY"; +pub const DRY_RUNNING_ENV: &str = "DRY_RUNNING"; +pub const RELAY_COUNT_FOR_RECHARGE_ENV: &str = "RELAY_COUNT_FOR_RECHARGE"; + +#[derive(Clone, Debug, Deserialize, Serialize)] +#[serde(transparent)] +pub struct SimpleServiceResponse { + pub message: String, +} + +impl SimpleServiceResponse { + pub fn from(message: &str) -> Json { + Json(Self { + message: message.to_string(), + }) + } +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct RelayResponse { + pub tx_hash: TxHash, +} + +impl RelayResponse { + pub fn from(tx_hash: TxHash) -> Json { + Json(Self { tx_hash }) + } +} + +#[derive(Clone, Debug, Deserialize, Serialize)] +pub struct RelayQuery { + pub id_hiding: U256, + pub amount: U256, + pub withdraw_address: Address, + pub merkle_root: U256, + pub nullifier_hash: U256, + pub new_note: U256, + pub proof: Bytes, +} + +/// The fee that the relayer charges for relaying a transaction. Currently set to 0.1 TZERO. +pub fn relayer_fee() -> U256 { + U256::from(ONE_TZERO / 10) +} diff --git a/crates/shielder-relayer/src/main.rs b/crates/shielder-relayer/src/main.rs new file mode 100644 index 00000000..15faa055 --- /dev/null +++ b/crates/shielder-relayer/src/main.rs @@ -0,0 +1,199 @@ +use std::{env, io, str::FromStr, sync::Arc}; + +use alloy_provider::Provider; +use alloy_signer_local::PrivateKeySigner; +use anyhow::{anyhow, Result}; +use axum::{ + middleware, + routing::{get, post}, + Router, +}; +use shielder_rust_sdk::{ + alloy_primitives::Address, + contract::{ + providers::create_provider_with_nonce_caching_signer, ConnectionPolicy, ShielderUser, + }, +}; +use tower_http::cors::CorsLayer; +use tracing::info; +use tracing_subscriber::EnvFilter; + +use crate::{ + config::{resolve_config, ChainConfig, LoggingFormat, NoncePolicy, ServerConfig}, + metrics::{prometheus_endpoint, setup_metrics_handle}, + monitor::{balance_monitor::balance_monitor, Balances}, + recharge::start_recharging_worker, + relay::Taskmaster, +}; + +mod config; +mod metrics; +mod monitor; +mod recharge; +mod relay; + +#[derive(Clone)] +pub struct AppState { + pub node_rpc_url: String, + pub fee_destination: Address, + pub signer_addresses: Vec
, + pub taskmaster: Taskmaster, + pub balances: Balances, +} + +struct Signers { + signers: Vec, + addresses: Vec
, + balances: Balances, +} + +#[tokio::main] +async fn main() -> Result<()> { + let server_config = resolve_config(); + init_logging(server_config.logging_format)?; + + let signers = get_signer_info(&server_config.chain)?; + + tokio::try_join!( + balance_monitor( + &server_config.chain.node_rpc_url, + server_config.operations.balance_monitor_interval_secs, + signers.balances.clone(), + ), + start_metrics_server(&server_config, signers.balances.clone()), + start_main_server(&server_config, signers), + )?; + + Ok(()) +} + +fn get_signer_info(config: &ChainConfig) -> Result { + let (signers, addresses) = parse_keys(&config.signing_keys)?; + let balances = Arc::new( + addresses + .iter() + .map(|address| (*address, Default::default())) + .collect(), + ); + Ok(Signers { + signers, + addresses, + balances, + }) +} + +async fn start_metrics_server(config: &ServerConfig, balances: Balances) -> Result<()> { + let address = config.network.metrics_address(); + let listener = tokio::net::TcpListener::bind(address.clone()).await?; + info!("Exposing metrics on {address}"); + + let metrics_handle = setup_metrics_handle()?; + let node_rpc_url = config.chain.node_rpc_url.clone(); + + let app = Router::new() + .route( + "/metrics", + get(move || prometheus_endpoint(metrics_handle, node_rpc_url, balances)), + ) + .layer(CorsLayer::permissive()); + Ok(axum::serve(listener, app).await?) +} + +async fn start_main_server(config: &ServerConfig, signers: Signers) -> Result<()> { + let address = config.network.main_address(); + let listener = tokio::net::TcpListener::bind(address.clone()).await?; + info!("Listening on {address}"); + + let fee_destination = signer(&config.chain.fee_destination_key)?; + let fee_destination_address = fee_destination.address(); + + let report_for_recharge = start_recharging_worker( + config.chain.node_rpc_url.clone(), + fee_destination, + signers.addresses.len(), + config.operations.relay_count_for_recharge, + ); + + let state = AppState { + node_rpc_url: config.chain.node_rpc_url.clone(), + fee_destination: fee_destination_address, + balances: signers.balances, + signer_addresses: signers.addresses, + taskmaster: Taskmaster::new( + build_shielder_users( + signers.signers, + &config.chain, + config.operations.nonce_policy, + ) + .await?, + config.operations.dry_running, + report_for_recharge, + ), + }; + + let app = Router::new() + .route("/health", get(monitor::endpoints::health_endpoint)) + .route("/relay", post(relay::relay)) + .with_state(state.clone()) + .route_layer(middleware::from_fn(metrics::request_metrics)) + .layer(CorsLayer::permissive()); + Ok(axum::serve(listener, app).await?) +} + +fn init_logging(format: LoggingFormat) -> Result<()> { + const LOG_CONFIGURATION_ENVVAR: &str = "RUST_LOG"; + + let filter = EnvFilter::new( + env::var(LOG_CONFIGURATION_ENVVAR) + .as_deref() + .unwrap_or("info"), + ); + + let subscriber = tracing_subscriber::fmt() + .with_writer(io::stdout) + .with_target(true) + .with_env_filter(filter); + + match format { + LoggingFormat::Json => subscriber.json().try_init(), + LoggingFormat::Text => subscriber.try_init(), + } + .map_err(|err| anyhow!(err)) +} + +fn parse_keys(keys: &[String]) -> Result<(Vec, Vec
)> { + let signers = keys + .iter() + .map(|key| signer(key)) + .collect::>>()?; + let addresses = signers.iter().map(|signer| signer.address()).collect(); + Ok((signers, addresses)) +} + +fn signer(signing_key: &str) -> Result { + PrivateKeySigner::from_str(signing_key) + .map_err(|err| anyhow!("Failed to create signer - invalid signing key: {err:?}")) +} + +async fn build_shielder_users( + signers: Vec, + config: &ChainConfig, + nonce_policy: NoncePolicy, +) -> Result>> { + let mut shielder_users = vec![]; + for signer in signers { + let policy = match nonce_policy { + NoncePolicy::Caching => ConnectionPolicy::Keep { + caller_address: signer.address(), + provider: create_provider_with_nonce_caching_signer(&config.node_rpc_url, signer) + .await?, + }, + NoncePolicy::Stateless => ConnectionPolicy::OnDemand { + signer, + rpc_url: config.node_rpc_url.clone(), + }, + }; + shielder_users.push(ShielderUser::new(config.shielder_contract_address, policy)); + } + Ok(shielder_users) +} diff --git a/crates/shielder-relayer/src/metrics.rs b/crates/shielder-relayer/src/metrics.rs new file mode 100644 index 00000000..25981eeb --- /dev/null +++ b/crates/shielder-relayer/src/metrics.rs @@ -0,0 +1,88 @@ +use std::{ops::Div, time::Instant}; + +use anyhow::Result; +use axum::{ + extract::{MatchedPath, Request}, + middleware::Next, + response::IntoResponse, +}; +use metrics_exporter_prometheus::{Matcher, PrometheusBuilder, PrometheusHandle}; +use shielder_rust_sdk::{alloy_primitives::U256, native_token::NATIVE_TOKEN_DECIMALS}; + +use crate::monitor::{healthy, Balances}; + +pub const TOTAL_REQUESTS_METRIC: &str = "http_requests_total"; +pub const REQUEST_DURATION_METRIC: &str = "http_requests_duration_seconds"; +pub const WITHDRAW_DRY_RUN_FAILURE: &str = "withdraw_dry_run_failure"; +pub const WITHDRAW_FAILURE: &str = "withdraw_failure"; +pub const WITHDRAW_SUCCESS: &str = "withdraw_success"; +pub const HEALTH: &str = "health"; +pub const SIGNER_BALANCES: &str = "signer_balances"; + +pub async fn prometheus_endpoint( + metrics_handle: PrometheusHandle, + node_rpc_url: String, + balances: Balances, +) -> impl IntoResponse { + metrics::gauge!(HEALTH).set(healthy(&node_rpc_url).await.is_ok() as u8 as f64); + render_signer_balances(balances).await; + + metrics_handle.render() +} + +async fn render_signer_balances(balances: Balances) { + for (signer, balance) in balances.iter() { + let balance = balance.read().await.unwrap_or_default(); + let tzero_balance = balance + .div(U256::from(10u128.pow(NATIVE_TOKEN_DECIMALS as u32))) + .to_string() + .parse::() + .unwrap_or(f64::NAN); + metrics::gauge!(SIGNER_BALANCES, "address" => signer.to_string()).set(tzero_balance); + } +} + +/// Setup Prometheus metrics handle with custom histogram buckets etc. +/// +/// Can be called only once, during server setup. +pub fn setup_metrics_handle() -> Result { + const EXPONENTIAL_SECONDS: &[f64] = &[ + 0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1.0, 2.5, 5.0, 10.0, 20.0, + ]; + + Ok(PrometheusBuilder::new() + .set_buckets_for_metric( + Matcher::Full(REQUEST_DURATION_METRIC.to_string()), + EXPONENTIAL_SECONDS, + )? + .install_recorder()?) +} + +/// Middleware to record HTTP request metrics. +pub async fn request_metrics(req: Request, next: Next) -> impl IntoResponse { + let path = get_request_path(&req); + let method = req.method().clone(); + + let start = Instant::now(); + let response = next.run(req).await; + let latency = start.elapsed().as_secs_f64(); + + let labels = [ + ("method", method.to_string()), + ("path", path), + ("status", response.status().as_u16().to_string()), + ]; + + metrics::counter!(TOTAL_REQUESTS_METRIC, &labels).increment(1); + metrics::histogram!(REQUEST_DURATION_METRIC, &labels).record(latency); + + response +} + +fn get_request_path(req: &Request) -> String { + if let Some(matched_path) = req.extensions().get::() { + matched_path.as_str().to_owned() + } else { + req.uri().path().to_owned() + } +} diff --git a/crates/shielder-relayer/src/monitor/balance_monitor.rs b/crates/shielder-relayer/src/monitor/balance_monitor.rs new file mode 100644 index 00000000..308ea401 --- /dev/null +++ b/crates/shielder-relayer/src/monitor/balance_monitor.rs @@ -0,0 +1,43 @@ +use alloy_provider::Provider; +use anyhow::Result; +use shielder_rust_sdk::{ + alloy_primitives::{Address, U256}, + contract::providers::create_simple_provider, +}; +use tokio::time::{interval, Duration}; +use tracing::error; + +use crate::monitor::Balances; + +/// Periodically check the balance of the relayer's signer addresses. +pub async fn balance_monitor( + node_rpc_url: &str, + interval_secs: u64, + balances: Balances, +) -> Result<()> { + let provider = create_simple_provider(node_rpc_url).await?; + let mut interval = interval(Duration::from_secs(interval_secs)); + + loop { + interval.tick().await; + for signer in balances.keys() { + match provider.get_balance(*signer).await { + Ok(balance) => { + set_balance(&balances, *signer, Some(balance)).await; + } + Err(err) => { + error!("Cannot reach RPC node: {err:?}. Cannot check balance for {signer}"); + set_balance(&balances, *signer, None).await; + } + } + } + } +} + +async fn set_balance(balances: &Balances, address: Address, balance: Option) { + *balances + .get(&address) + .expect("Map should be already intialized") + .write() + .await = balance; +} diff --git a/crates/shielder-relayer/src/monitor/endpoints.rs b/crates/shielder-relayer/src/monitor/endpoints.rs new file mode 100644 index 00000000..ff3c3404 --- /dev/null +++ b/crates/shielder-relayer/src/monitor/endpoints.rs @@ -0,0 +1,21 @@ +use axum::{extract::State, http::StatusCode, response::IntoResponse, Json}; +use shielder_relayer::SimpleServiceResponse; +use tracing::{debug, error}; + +use crate::{monitor::healthy, AppState}; + +pub async fn health_endpoint(app_state: State) -> impl IntoResponse { + debug!("Healthcheck request received"); + match healthy(&app_state.node_rpc_url).await { + Ok(()) => (StatusCode::OK, SimpleServiceResponse::from("Healthy")), + Err(err) => service_unavailable(&err), + } +} + +fn service_unavailable(msg: &str) -> (StatusCode, Json) { + error!(msg); + ( + StatusCode::SERVICE_UNAVAILABLE, + SimpleServiceResponse::from(msg), + ) +} diff --git a/crates/shielder-relayer/src/monitor/mod.rs b/crates/shielder-relayer/src/monitor/mod.rs new file mode 100644 index 00000000..3d8a603a --- /dev/null +++ b/crates/shielder-relayer/src/monitor/mod.rs @@ -0,0 +1,28 @@ +use std::{collections::HashMap, fmt::Debug, sync::Arc}; + +use alloy_provider::Provider; +use shielder_rust_sdk::{ + alloy_primitives::{Address, U256}, + contract::providers::create_simple_provider, +}; +use tokio::sync::RwLock; + +pub mod balance_monitor; +pub mod endpoints; + +pub type Balances = Arc>>>; + +/// Check if the RPC node is reachable. +pub async fn healthy(node_rpc_url: &str) -> Result<(), String> { + match create_simple_provider(node_rpc_url).await { + Ok(provider) => match provider.get_chain_id().await { + Ok(_) => Ok(()), + Err(err) => cannot_reach_rpc_node(err), + }, + Err(err) => cannot_reach_rpc_node(err), + } +} + +fn cannot_reach_rpc_node(err: E) -> Result<(), String> { + Err(format!("Cannot reach RPC node: {err:?}")) +} diff --git a/crates/shielder-relayer/src/recharge.rs b/crates/shielder-relayer/src/recharge.rs new file mode 100644 index 00000000..7bf85eb9 --- /dev/null +++ b/crates/shielder-relayer/src/recharge.rs @@ -0,0 +1,82 @@ +use std::collections::HashMap; + +use alloy_provider::{network::TransactionBuilder, Provider}; +use alloy_rpc_types::TransactionRequest; +use alloy_signer_local::PrivateKeySigner; +use anyhow::{bail, Result}; +use shielder_relayer::relayer_fee; +use shielder_rust_sdk::{ + alloy_primitives::{Address, U256}, + contract::providers::create_provider_with_nonce_caching_signer, +}; +use tokio::sync::mpsc::{self, Receiver as MPSCReceiver, Sender as MPSCSender}; +use tracing::{error, info}; + +const RECHARGE_AS_FEE_PERCENT: u32 = 70; + +pub fn start_recharging_worker( + node_rpc_url: String, + cornucopia: PrivateKeySigner, + relay_workers: usize, + relay_count_for_recharge: u32, +) -> MPSCSender
{ + let (relay_report_sender, relay_report_receiver) = mpsc::channel(relay_workers); + tokio::spawn(recharging_worker( + node_rpc_url, + cornucopia, + relay_report_receiver, + relay_count_for_recharge, + )); + + relay_report_sender +} + +async fn recharging_worker( + node_rpc_url: String, + cornucopia: PrivateKeySigner, + mut relay_reports: MPSCReceiver
, + relay_count_for_recharge: u32, +) -> Result<()> { + let cornucopia_address = cornucopia.address(); + let provider = create_provider_with_nonce_caching_signer(&node_rpc_url, cornucopia).await?; + let mut accounting = HashMap::::new(); + + while let Some(relayer) = relay_reports.recv().await { + let count = accounting.entry(relayer).or_insert(0); + *count += 1; + info!("Relayer {relayer} reported that it sent a relay tx. Current counter: {count}"); + + if *count >= relay_count_for_recharge { + match recharge_relayer(&provider, relayer, cornucopia_address, *count).await { + Ok(recharge_amount) => { + info!("Recharged relayer {relayer} with {recharge_amount}"); + } + Err(e) => { + error!("Failed to recharge relayer {relayer}: {e:?}"); + } + } + *count = 0; + } + } + + error!("Relay report channel closed"); + bail!("Relay report channel closed"); +} + +async fn recharge_relayer( + provider: &impl Provider, + relayer: Address, + cornucopia_address: Address, + relay_count: u32, +) -> Result { + let recharge_amount = U256::from(relay_count) + * (relayer_fee() * U256::from(RECHARGE_AS_FEE_PERCENT) / U256::from(100)); + + let tx = TransactionRequest::default() + .with_from(cornucopia_address) + .with_value(recharge_amount) + .with_to(relayer); + + provider.send_transaction(tx).await?.watch().await?; + Ok(recharge_amount) +} diff --git a/crates/shielder-relayer/src/relay/mod.rs b/crates/shielder-relayer/src/relay/mod.rs new file mode 100644 index 00000000..98a46bb7 --- /dev/null +++ b/crates/shielder-relayer/src/relay/mod.rs @@ -0,0 +1,85 @@ +use axum::{ + extract::State, + http::StatusCode, + response::{IntoResponse, Response}, + Json, +}; +use shielder_relayer::{relayer_fee, RelayQuery, RelayResponse, SimpleServiceResponse}; +use shielder_rust_sdk::{ + alloy_primitives::Address, contract::ShielderContract::withdrawNativeCall, +}; +use tracing::{debug, error}; + +pub use crate::relay::taskmaster::Taskmaster; +use crate::{ + metrics::WITHDRAW_FAILURE, + relay::{request_trace::RequestTrace, taskmaster::TaskResult}, + AppState, +}; + +mod monitoring; +mod request_trace; +mod taskmaster; + +const TASK_QUEUE_SIZE: usize = 1024; +const OPTIMISTIC_DRY_RUN_THRESHOLD: u32 = 32; + +pub async fn relay(app_state: State, Json(query): Json) -> impl IntoResponse { + debug!("Relay request received: {query:?}"); + let request_trace = RequestTrace::new(&query); + + let withdraw_call = create_call(query, app_state.fee_destination); + let Ok(rx) = app_state + .taskmaster + .register_new_task(withdraw_call, request_trace) + .await + else { + error!("Failed to register new task"); + return server_error("Failed to register new task"); + }; + + match rx.await { + Ok((mut request_trace, task_result)) => match task_result { + TaskResult::Ok(tx_hash) => { + request_trace.record_success(tx_hash); + (StatusCode::OK, RelayResponse::from(tx_hash)).into_response() + } + TaskResult::DryRunFailed(err) => { + request_trace.record_dry_run_failure(err); + bad_request("Dry run failed") + } + TaskResult::RelayFailed(err) => { + request_trace.record_failure(err); + bad_request("Relay failed") + } + }, + Err(err) => { + error!("[UNEXPECTED] Relay task master failed: {err}"); + metrics::counter!(WITHDRAW_FAILURE).increment(1); + server_error("Relay task failed") + } + } +} + +fn bad_request(msg: &str) -> Response { + (StatusCode::BAD_REQUEST, SimpleServiceResponse::from(msg)).into_response() +} + +fn server_error(msg: &str) -> Response { + let code = StatusCode::INTERNAL_SERVER_ERROR; + (code, SimpleServiceResponse::from(msg)).into_response() +} + +fn create_call(q: RelayQuery, relayer_address: Address) -> withdrawNativeCall { + withdrawNativeCall { + idHiding: q.id_hiding, + withdrawAddress: q.withdraw_address, + relayerAddress: relayer_address, + relayerFee: relayer_fee(), + amount: q.amount, + merkleRoot: q.merkle_root, + oldNullifierHash: q.nullifier_hash, + newNote: q.new_note, + proof: q.proof, + } +} diff --git a/crates/shielder-relayer/src/relay/monitoring.rs b/crates/shielder-relayer/src/relay/monitoring.rs new file mode 100644 index 00000000..8df751d9 --- /dev/null +++ b/crates/shielder-relayer/src/relay/monitoring.rs @@ -0,0 +1,56 @@ +use std::sync::{ + atomic::{AtomicU32, Ordering}, + Arc, +}; + +use tracing::warn; + +use crate::relay::OPTIMISTIC_DRY_RUN_THRESHOLD; + +pub trait RelayingMonitoring: Clone + Send { + fn notice_relay_success(&mut self) {} + fn notice_relay_failure(&mut self) {} +} + +pub trait DryRunSwitch: Clone + Send { + fn should_dry_run_now(&self) -> bool { + true + } +} + +#[derive(Copy, Clone)] +pub struct ObligatoryDryRun; + +impl RelayingMonitoring for ObligatoryDryRun {} + +impl DryRunSwitch for ObligatoryDryRun {} + +#[derive(Clone)] +pub struct OptionalDryRun { + success_counter: Arc, +} + +impl OptionalDryRun { + pub fn new() -> Self { + Self { + success_counter: Arc::new(AtomicU32::new(OPTIMISTIC_DRY_RUN_THRESHOLD)), + } + } +} + +impl RelayingMonitoring for OptionalDryRun { + fn notice_relay_success(&mut self) { + self.success_counter.fetch_add(1, Ordering::Relaxed); + } + + fn notice_relay_failure(&mut self) { + warn!("Relay failed, turning on dry run"); + self.success_counter.store(0, Ordering::Relaxed); + } +} + +impl DryRunSwitch for OptionalDryRun { + fn should_dry_run_now(&self) -> bool { + self.success_counter.load(Ordering::Relaxed) < OPTIMISTIC_DRY_RUN_THRESHOLD + } +} diff --git a/crates/shielder-relayer/src/relay/request_trace.rs b/crates/shielder-relayer/src/relay/request_trace.rs new file mode 100644 index 00000000..d0e82dde --- /dev/null +++ b/crates/shielder-relayer/src/relay/request_trace.rs @@ -0,0 +1,104 @@ +use std::time::{Duration, Instant}; + +use shielder_relayer::RelayQuery; +use shielder_rust_sdk::{ + alloy_primitives::{Address, TxHash, U256}, + contract::ShielderContractError, +}; +use tracing::{error, info}; + +use crate::metrics::{WITHDRAW_DRY_RUN_FAILURE, WITHDRAW_FAILURE, WITHDRAW_SUCCESS}; + +type Measurement = (String, Duration); + +pub struct RequestTrace { + created_note: U256, + + measurements: Vec, + last_timestamp: Instant, + current_state: &'static str, + + relayer_address: Option
, + status: Option<&'static str>, + tx_hash: Option, +} + +impl RequestTrace { + pub fn new(relay_query: &RelayQuery) -> Self { + Self { + created_note: relay_query.new_note, + measurements: Vec::new(), + last_timestamp: Instant::now(), + current_state: "created", + relayer_address: None, + status: None, + tx_hash: None, + } + } + + pub fn record(&mut self, new_state: &'static str) { + if let Some(status) = self.status { + error!("RequestTrace is already finished with status: {}", status); + } + + let duration = self.last_timestamp.elapsed(); + self.measurements + .push((format!("[{} -> {new_state}]", self.current_state), duration)); + self.current_state = new_state; + self.last_timestamp = Instant::now(); + } + + pub fn set_relayer_address(&mut self, relayer: Address) { + self.relayer_address = Some(relayer); + } + + pub fn record_success(&mut self, tx_hash: TxHash) { + metrics::counter!(WITHDRAW_SUCCESS).increment(1); + self.tx_hash = Some(tx_hash); + self.finish("✅ SUCCESS"); + } + + pub fn record_failure(&mut self, err: ShielderContractError) { + metrics::counter!(WITHDRAW_FAILURE).increment(1); + error!("Relay failed: {err}"); + self.finish("❌ FAILURE"); + } + + pub fn record_dry_run_failure(&mut self, err: ShielderContractError) { + metrics::counter!(WITHDRAW_DRY_RUN_FAILURE).increment(1); + info!("Relay dry-run failed: {err}"); + self.finish("❌ DRY-RUN FAILURE"); + } + + fn finish(&mut self, status: &'static str) { + self.record("finished"); + self.status = Some(status); + } +} + +impl Drop for RequestTrace { + fn drop(&mut self) { + let tx_hash = match self.tx_hash { + Some(tx_hash) => tx_hash.to_string(), + None => "No tx hash set".to_string(), + }; + let relayer_address = match self.relayer_address { + Some(address) => address.to_string(), + None => "No relayer address set".to_string(), + }; + let measurements = self + .measurements + .iter() + .map(|(state, duration)| format!("{state}: {duration:?}")) + .collect::>(); + + info!( + status = self.status.unwrap_or("in progress"), + created_note = %self.created_note, + tx_hash = tx_hash, + relayer_address = %relayer_address, + measurements = ?measurements, + "Request trace", + ); + } +} diff --git a/crates/shielder-relayer/src/relay/taskmaster.rs b/crates/shielder-relayer/src/relay/taskmaster.rs new file mode 100644 index 00000000..3bee5577 --- /dev/null +++ b/crates/shielder-relayer/src/relay/taskmaster.rs @@ -0,0 +1,165 @@ +use alloy_provider::Provider; +use anyhow::Result; +use async_channel::{Receiver as MPMCReceiver, Sender as MPMCSender}; +use shielder_rust_sdk::{ + alloy_primitives::{Address, TxHash}, + contract::{ + call_type::{DryRun, Submit}, + ShielderContract::withdrawNativeCall, + ShielderContractError, ShielderUser, + }, +}; +use tokio::sync::{ + mpsc::Sender as MPSCSender, + oneshot, + oneshot::{Receiver as OneshotReceiver, Sender as OneshotSender}, +}; +use tracing::{error, info}; + +use crate::{ + config::DryRunning, + relay::{ + monitoring::{DryRunSwitch, ObligatoryDryRun, OptionalDryRun, RelayingMonitoring}, + request_trace::RequestTrace, + TASK_QUEUE_SIZE, + }, +}; + +pub enum TaskResult { + DryRunFailed(ShielderContractError), + RelayFailed(ShielderContractError), + Ok(TxHash), +} + +pub struct Task { + report: OneshotSender<(RequestTrace, TaskResult)>, + payload: withdrawNativeCall, + request_trace: RequestTrace, +} + +#[derive(Clone)] +pub struct Taskmaster { + task_sender: MPMCSender, +} + +impl Taskmaster { + pub fn new( + shielder_users: Vec>, + dry_running: DryRunning, + recharge_reporter: MPSCSender
, + ) -> Self { + let (task_sender, task_receiver) = async_channel::bounded(TASK_QUEUE_SIZE); + + match dry_running { + DryRunning::Always => { + info!("Dry running is turned on for all calls"); + Self::spawn_workers( + shielder_users, + task_receiver, + ObligatoryDryRun {}, + recharge_reporter, + ); + } + DryRunning::Optimistic => { + info!("Dry running is optimistically disabled."); + Self::spawn_workers( + shielder_users, + task_receiver, + OptionalDryRun::new(), + recharge_reporter, + ); + } + } + + Self { task_sender } + } + + fn spawn_workers( + shielder_users: Vec>, + task_receiver: MPMCReceiver, + dry_run_manager: impl RelayingMonitoring + DryRunSwitch + 'static, + recharge_reporter: MPSCSender
, + ) { + for shielder_user in shielder_users { + tokio::spawn(relay_worker( + task_receiver.clone(), + shielder_user, + dry_run_manager.clone(), + recharge_reporter.clone(), + )); + } + } + + pub async fn register_new_task( + &self, + payload: withdrawNativeCall, + mut request_trace: RequestTrace, + ) -> Result> { + let (report_sender, report_receiver) = oneshot::channel(); + + request_trace.record("queued for relay"); + let task = Task { + report: report_sender, + payload, + request_trace, + }; + self.task_sender + .send(task) + .await + .map_err(|_| anyhow::anyhow!("Failed to send task to relay"))?; + + Ok(report_receiver) + } +} + +async fn relay_worker( + requests: MPMCReceiver, + shielder_user: ShielderUser, + mut dry_run_manager: impl RelayingMonitoring + DryRunSwitch, + recharge_reporter: MPSCSender
, +) { + let worker_address = shielder_user.address(); + while let Ok(task) = requests.recv().await { + let mut request_trace = task.request_trace; + request_trace.record("received by worker"); + request_trace.set_relayer_address(worker_address); + + if dry_run_manager.should_dry_run_now() { + let dry_run_result = shielder_user + .withdraw_native::(task.payload.clone()) + .await; + request_trace.record("dry run completed"); + + if let Err(err) = dry_run_result { + let _ = task + .report + .send((request_trace, TaskResult::DryRunFailed(err))); + continue; + } + } + + let submit_result = shielder_user.withdraw_native::(task.payload).await; + request_trace.record("relay completed"); + + match submit_result { + Ok(tx_hash) => { + let _ = task.report.send((request_trace, TaskResult::Ok(tx_hash))); + dry_run_manager.notice_relay_success(); + } + Err(err) => { + let _ = task + .report + .send((request_trace, TaskResult::RelayFailed(err))); + dry_run_manager.notice_relay_failure(); + } + }; + if let Err(err) = recharge_reporter.send(worker_address).await { + error!( + relay_worker = ?worker_address, + "Failed to report relay to recharge worker: {err}" + ); + } + } + + error!("Relay worker thread stopped working - channel closed. Corresponding address: {worker_address}"); +} diff --git a/crates/shielder-relayer/test-resources/AcceptingShielder.sol b/crates/shielder-relayer/test-resources/AcceptingShielder.sol new file mode 100644 index 00000000..c6e32bd9 --- /dev/null +++ b/crates/shielder-relayer/test-resources/AcceptingShielder.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +contract AcceptingShielder { + function withdrawNative( + uint256 idHiding, + uint256 amount, + address withdrawAddress, + uint256 merkleRoot, + uint256 nullifier, + uint256 newNote, + bytes calldata proof, + address relayer, + uint256 relayerFee + ) external {} +} diff --git a/crates/shielder-relayer/test-resources/RevertingShielder.sol b/crates/shielder-relayer/test-resources/RevertingShielder.sol new file mode 100644 index 00000000..fc696ae4 --- /dev/null +++ b/crates/shielder-relayer/test-resources/RevertingShielder.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.20; + +contract RevertingShielder { + function withdrawNative( + uint256 idHiding, + uint256 amount, + address withdrawAddress, + uint256 merkleRoot, + uint256 nullifier, + uint256 newNote, + bytes calldata proof, + address relayer, + uint256 relayerFee + ) external { + revert(); + } +} diff --git a/crates/shielder-relayer/test.sh b/crates/shielder-relayer/test.sh new file mode 100755 index 00000000..7b206f33 --- /dev/null +++ b/crates/shielder-relayer/test.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash + +set -u + +NODE_RPC_PORT=8545 +NODE_RPC_URL="http://localhost:${NODE_RPC_PORT}" +DEPLOYER_PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 + +########################## Start anvil ######################################### + +../../scripts/aleph-anvil.sh --port "${NODE_RPC_PORT}" 1> /dev/null 2>&1 + +########################## Deploy contracts and setup caller ################### +ACCEPTING_SHIELDER=$(forge create -r "${NODE_RPC_URL}" --private-key "${DEPLOYER_PRIVATE_KEY}" crates/shielder-relayer/test-resources/AcceptingShielder.sol:AcceptingShielder --json | jq -r '.deployedTo') +REVERTING_SHIELDER=$(forge create -r "${NODE_RPC_URL}" --private-key "${DEPLOYER_PRIVATE_KEY}" crates/shielder-relayer/test-resources/RevertingShielder.sol:RevertingShielder --json | jq -r '.deployedTo') + +########################## Run tests ########################################### +export ACCEPTING_SHIELDER +export REVERTING_SHIELDER +export NODE_RPC_URL + +cargo test --release -- --show-output --test-threads 1 +TEST_RESULT=$? + +########################## Stop anvil ########################################## +anvil_pid=$(pgrep -f 'anvil' || true) +if [ -n "$anvil_pid" ]; then + kill "${anvil_pid}" +fi + +########################## Exit with the same code as cargo test ############### +exit $TEST_RESULT diff --git a/crates/shielder-relayer/tests/component_tests.rs b/crates/shielder-relayer/tests/component_tests.rs new file mode 100644 index 00000000..35bb3748 --- /dev/null +++ b/crates/shielder-relayer/tests/component_tests.rs @@ -0,0 +1,133 @@ +use reqwest::{Response, StatusCode}; +use shielder_relayer::{RelayResponse, SimpleServiceResponse}; + +use crate::utils::{ + config::{NodeRpcUrl, RelayerSigner, ShielderContract, TestConfig, POOR_ADDRESS, SIGNER}, + container_logs, response_message, TestContext, +}; + +mod utils; + +async fn simple_payload(response: Response) -> String { + response_message::(response) + .await + .message +} + +fn standard_config() -> TestConfig { + TestConfig { + shielder_contract: ShielderContract::Accepting, + relayer_signer: RelayerSigner::Endowed, + node_rpc_url: NodeRpcUrl::Valid, + } +} + +#[tokio::test(flavor = "multi_thread")] +async fn in_correct_setting_service_is_healthy_and_signers_have_funds() { + let test_context = TestContext::new(standard_config()).await; + + let health_response = test_context.reach_health().await; + ctx_assert!(health_response.status().is_success(), test_context); + ctx_assert_eq!( + simple_payload(health_response).await, + "Healthy", + test_context + ); + + let metrics = test_context.get_metrics().await; + ctx_assert!( + metrics.contains(&format!("signer_balances{{address=\"{SIGNER}\"}} 10000")), + test_context + ); +} + +#[tokio::test(flavor = "multi_thread")] +async fn when_cannot_connect_to_chain_service_is_not_healthy_and_signers_have_no_balance() { + let test_context = TestContext::new(TestConfig { + node_rpc_url: NodeRpcUrl::Unavailable, + ..standard_config() + }) + .await; + + let health_response = test_context.reach_health().await; + ctx_assert_eq!( + health_response.status(), + StatusCode::SERVICE_UNAVAILABLE, + test_context + ); + ctx_assert!( + simple_payload(health_response) + .await + .starts_with("Cannot reach RPC node"), + test_context + ); + + let metrics = test_context.get_metrics().await; + ctx_assert!( + metrics.contains(&format!("signer_balances{{address=\"{SIGNER}\"}} 0")), + test_context + ); +} + +#[tokio::test(flavor = "multi_thread")] +async fn when_relayer_signer_does_not_have_enough_funds_service_is_healthy() { + let config = TestConfig { + relayer_signer: RelayerSigner::NotEndowed, + ..standard_config() + }; + let test_context = TestContext::new(config).await; + + let health_response = test_context.reach_health().await; + ctx_assert!(health_response.status().is_success(), test_context); + ctx_assert_eq!( + simple_payload(health_response).await, + "Healthy", + test_context + ); + + let metrics = test_context.get_metrics().await; + ctx_assert!( + metrics.contains(&format!("signer_balances{{address=\"{POOR_ADDRESS}\"}} 0")), + test_context + ); +} + +#[tokio::test(flavor = "multi_thread")] +async fn when_contract_returns_ok_server_sings_success() { + let test_context = TestContext::new(standard_config()).await; + let response = test_context.relay().await; + + ctx_assert!(response.status().is_success(), test_context); + response_message::(response).await; +} + +#[tokio::test(flavor = "multi_thread")] +async fn when_contract_reverts_server_screams_failure() { + let config = TestConfig { + shielder_contract: ShielderContract::Reverting, + ..standard_config() + }; + let test_context = TestContext::new(config).await; + let response = test_context.relay().await; + + ctx_assert_eq!(response.status(), StatusCode::BAD_REQUEST, test_context); + ctx_assert_eq!( + simple_payload(response).await, + "Dry run failed", + test_context + ); +} + +#[tokio::test(flavor = "multi_thread")] +async fn metrics_register_withdrawals() { + let context = TestContext::new(standard_config()).await; + + context.relay().await; + context.relay().await; + + let metrics = context.get_metrics().await; + ctx_assert!( + metrics.contains("# TYPE withdraw_success counter\nwithdraw_success 2"), + context + ); +} diff --git a/crates/shielder-relayer/tests/utils/config.rs b/crates/shielder-relayer/tests/utils/config.rs new file mode 100644 index 00000000..b7514188 --- /dev/null +++ b/crates/shielder-relayer/tests/utils/config.rs @@ -0,0 +1,75 @@ +use std::env; + +/// Base URL of relayer: we are running containers in the network host mode. +pub const BASE_URL: &str = "http://127.0.0.1"; +/// Public key of some already endowed account on the test network. +pub const FEE_DESTINATION: &str = "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266"; +/// Corresponding private key. +pub const FEE_DESTINATION_KEY: &str = + "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"; +/// Public key of another already endowed account on the test network. +pub const SIGNER: &str = "0x70997970C51812dc3A010C7d01b50e0d17dc79C8"; +/// Corresponding private key. +pub const SIGNER_KEY: &str = "0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d"; +/// Private key of an account with no funds. +pub const POOR_ADDRESS_SIGNING_KEY: &str = + "0xfb50646599b16cb2e58b158f4b54d85a29d5fe4e210c6b6d5e0717dccd7c7584"; +/// Corresponding address. +pub const POOR_ADDRESS: &str = "0x5e9428AC5Cf0FA8822372D8FeA88d548dc3F2Ef3"; + +fn get_env(name: &str) -> String { + env::var(name).unwrap_or_else(|_| panic!("{name} env var is not set")) +} + +#[derive(Copy, Clone)] +pub enum ShielderContract { + Accepting, + Reverting, +} + +impl ShielderContract { + pub fn address(&self) -> String { + let env_name = match self { + ShielderContract::Accepting => "ACCEPTING_SHIELDER", + ShielderContract::Reverting => "REVERTING_SHIELDER", + }; + get_env(env_name) + } +} + +#[derive(Copy, Clone)] +pub enum RelayerSigner { + Endowed, + NotEndowed, +} + +impl RelayerSigner { + pub fn signing_key(&self) -> String { + match self { + RelayerSigner::Endowed => SIGNER_KEY.to_string(), + RelayerSigner::NotEndowed => POOR_ADDRESS_SIGNING_KEY.to_string(), + } + } +} + +#[derive(Copy, Clone)] +pub enum NodeRpcUrl { + Valid, + Unavailable, +} + +impl NodeRpcUrl { + pub fn url(&self) -> String { + match self { + NodeRpcUrl::Valid => get_env("NODE_RPC_URL"), + NodeRpcUrl::Unavailable => String::from("https://non-existent.node/"), + } + } +} + +#[derive(Copy, Clone)] +pub struct TestConfig { + pub shielder_contract: ShielderContract, + pub relayer_signer: RelayerSigner, + pub node_rpc_url: NodeRpcUrl, +} diff --git a/crates/shielder-relayer/tests/utils/mod.rs b/crates/shielder-relayer/tests/utils/mod.rs new file mode 100644 index 00000000..71f5f4f5 --- /dev/null +++ b/crates/shielder-relayer/tests/utils/mod.rs @@ -0,0 +1,165 @@ +#![allow(unused)] + +use std::{net::TcpListener, str::FromStr}; + +use rand::Rng; +use reqwest::Response; +use serde::{Deserialize, Serialize}; +use shielder_relayer::RelayQuery; +use shielder_rust_sdk::alloy_primitives::{Address, Bytes, U256}; +use testcontainers::{ + core::IntoContainerPort, runners::AsyncRunner, ContainerAsync, ContainerRequest, Image, + ImageExt, TestcontainersError, +}; + +use crate::{ + ctx_assert, + utils::{ + config::{TestConfig, BASE_URL, FEE_DESTINATION, FEE_DESTINATION_KEY}, + relayer_image::RelayerImage, + }, +}; + +pub mod config; +pub mod relayer_image; + +/// Dockerized testing environment. +pub struct TestContext { + /// The running container with the relayer service. + pub relayer_container: ContainerAsync, + /// Exposed HTTP port of the relayer service. + pub relayer_port: u16, + /// Exposed HTTP port of the relayer's metrics. + pub relayer_metrics_port: u16, +} + +impl TestContext { + /// Creates new `TestContext`. + /// + /// # Networking and ports + /// + /// We are all containers in the host network. Therefore, to allow for parallel test execution, + /// we are choosing random ports (and ignoring potential conflicts). + pub async fn new(test_config: TestConfig) -> Self { + let port = get_free_port(); + let metrics_port = get_free_port(); + let relayer_container = ContainerRequest::from(RelayerImage::new( + port, + metrics_port, + test_config.node_rpc_url.url(), + test_config.shielder_contract.address(), + FEE_DESTINATION_KEY.to_string(), + test_config.relayer_signer.signing_key(), + )); + + Self { + relayer_container: start_container(relayer_container).await, + relayer_port: port, + relayer_metrics_port: metrics_port, + } + } + + pub async fn relay(&self) -> Response { + reqwest::Client::new() + .post(format!("{BASE_URL}:{}/relay", self.relayer_port)) + .json(&RelayQuery { + id_hiding: U256::ZERO, + amount: U256::from(1), + withdraw_address: Address::from_str(FEE_DESTINATION).unwrap(), + merkle_root: U256::ZERO, + nullifier_hash: U256::ZERO, + new_note: U256::ZERO, + proof: Bytes::new(), + }) + .send() + .await + .expect("Failed to reach relay endpoint") + } + + pub async fn get_metrics(&self) -> String { + let response = self.get("metrics", self.relayer_metrics_port).await; + ctx_assert!(response.status().is_success(), self); + response.text().await.unwrap() + } + + pub async fn reach_health(&self) -> Response { + self.get("health", self.relayer_port).await + } + + async fn get(&self, path: &str, port: u16) -> Response { + reqwest::Client::new() + .get(format!("{BASE_URL}:{}/{path}", port)) + .send() + .await + .unwrap_or_else(|_| panic!("Failed to reach `{path}` endpoint")) + } +} + +fn get_free_port() -> u16 { + // We go with a bounded number of attempts to avoid infinite loops in case of some network + // issues. + for _ in 0..100 { + let port = rand::thread_rng().gen_range(10000..60000); + if TcpListener::bind(("127.0.0.1", port)).is_ok() { + return port; + } + } + panic!("Failed to find a free port") +} + +async fn start_container(container: ContainerRequest) -> ContainerAsync { + container + .with_network("host") + .start() + .await + .expect("Failed to start container") +} + +pub async fn response_message Deserialize<'a>>( + response: Response, +) -> ResponseBody { + response + .json::() + .await + .expect("Failed to get response json body") +} + +pub async fn container_logs(container: &ContainerAsync) -> String { + let mut logs = String::new(); + + let mut handle_logs = |res: Result, TestcontainersError>, name| { + let bytes = res.unwrap_or_else(|_| panic!("Failed to get container {name} logs")); + logs += &format!( + "Container {name} logs:\n{}", + String::from_utf8_lossy(&bytes) + ); + }; + + handle_logs(container.stdout_to_vec().await, "stdout"); + handle_logs(container.stderr_to_vec().await, "stderr"); + + logs +} + +#[macro_export] +macro_rules! ctx_assert { + ($cond:expr, $context:expr) => { + assert!( + $cond, + "{}", + container_logs(&$context.relayer_container).await + ); + }; +} + +#[macro_export] +macro_rules! ctx_assert_eq { + ($left:expr, $right:expr, $context:expr) => { + assert_eq!( + $left, + $right, + "{}", + container_logs(&$context.relayer_container).await + ); + }; +} diff --git a/crates/shielder-relayer/tests/utils/relayer_image.rs b/crates/shielder-relayer/tests/utils/relayer_image.rs new file mode 100644 index 00000000..54cdc18d --- /dev/null +++ b/crates/shielder-relayer/tests/utils/relayer_image.rs @@ -0,0 +1,69 @@ +use std::{borrow::Cow, collections::HashMap, fmt::Display}; + +use shielder_relayer::{ + FEE_DESTINATION_KEY_ENV, NODE_RPC_URL_ENV, RELAYER_METRICS_PORT_ENV, RELAYER_PORT_ENV, + RELAYER_SIGNING_KEYS_ENV, SHIELDER_CONTRACT_ADDRESS_ENV, +}; +use testcontainers::{core::WaitFor, Image}; + +/// Wrapper around `shielder-relayer` Docker image. +/// +/// # Building image +/// +/// Run `make build-relayer-image` in the main repo directory. +/// +/// # Ready conditions +/// +/// We consider a container healthy after `Listening on ` is written to stdout. +#[derive(Debug)] +pub struct RelayerImage { + env_vars: HashMap, +} + +impl RelayerImage { + pub fn new( + port: u16, + metrics_port: u16, + node_rpc_url: String, + shielder_address: String, + fee_destination_key: String, + signing_key: String, + ) -> Self { + Self { + env_vars: HashMap::from([ + (RELAYER_PORT_ENV.to_string(), format!("{port}")), + ( + RELAYER_METRICS_PORT_ENV.to_string(), + format!("{metrics_port}"), + ), + (NODE_RPC_URL_ENV.to_string(), node_rpc_url), + (SHIELDER_CONTRACT_ADDRESS_ENV.to_string(), shielder_address), + (FEE_DESTINATION_KEY_ENV.to_string(), fee_destination_key), + (RELAYER_SIGNING_KEYS_ENV.to_string(), signing_key), + ]), + } + } +} + +impl Image for RelayerImage { + fn name(&self) -> &str { + "shielder-relayer" + } + + fn tag(&self) -> &str { + "latest" + } + + fn ready_conditions(&self) -> Vec { + vec![ + WaitFor::message_on_stdout("Listening on "), + WaitFor::message_on_stdout("Exposing metrics on "), + ] + } + + fn env_vars( + &self, + ) -> impl IntoIterator>, impl Into>)> { + Box::new(self.env_vars.iter()) + } +} diff --git a/crates/shielder-rust-sdk/Cargo.toml b/crates/shielder-rust-sdk/Cargo.toml new file mode 100644 index 00000000..e72d6842 --- /dev/null +++ b/crates/shielder-rust-sdk/Cargo.toml @@ -0,0 +1,91 @@ +[package] +name = "shielder-rust-sdk" +version = "0.1.0" +edition.workspace = true +authors.workspace = true +homepage.workspace = true +license.workspace = true +categories.workspace = true +repository.workspace = true +description = "Rust SDK for zkOS Shielder contract" + +[dependencies] +alloy-contract = { workspace = true, optional = true } +alloy-network = { workspace = true, optional = true } +alloy-primitives = { workspace = true, features = ["serde"], optional = true } +alloy-provider = { workspace = true, optional = true } +alloy-rpc-types = { workspace = true, optional = true } +alloy-signer-local = { workspace = true, optional = true } +alloy-sol-types = { workspace = true, optional = true } +alloy-transport = { workspace = true, optional = true } +anyhow = { workspace = true, optional = true } +byteorder = { workspace = true, optional = true } +halo2_proofs = { workspace = true, optional = true } +halo2curves = { workspace = true, optional = true } +hex = { workspace = true, optional = true } +lazy_static = { workspace = true, optional = true } +log = { workspace = true, optional = true } +num-bigint = { workspace = true, optional = true } +rand = { workspace = true, features = ["small_rng"], optional = true } +secp256k1 = { workspace = true, features = ["recovery"], optional = true } +serde = { workspace = true, features = ["derive"], optional = true } +sha3 = { workspace = true, optional = true } +shielder-circuits = { workspace = true, optional = true } +static_assertions = { workspace = true, optional = true } +thiserror = { workspace = true, optional = true } +tracing = { workspace = true, optional = true } + +[dev-dependencies] +alloy-primitives = {workspace = true, features = ["rand"]} +mockall = { workspace = true } +tokio = { workspace = true } +rand = { workspace = true } + +[features] +account = [ + "alloy-primitives", + "serde", + "sha3", + "shielder-circuits", + "static_assertions", +] +contract = [ + "alloy-primitives", + "alloy-contract", + "alloy-network", + "alloy-provider", + "alloy-rpc-types", + "alloy-sol-types", + "alloy-signer-local", + "alloy-transport", + "anyhow", + "conversion", + "log", + "rand", + "thiserror", + "tracing" +] +conversion = [ + "alloy-primitives", + "halo2curves", + "thiserror", +] +native_token = [] +parameter_generation = [ + "rand" +] +permit2 = [ + "alloy-primitives", + "alloy-sol-types", + "hex", + "lazy_static", + "secp256k1", +] +eip_155 = [] +powers_of_tau = [ + "byteorder", + "halo2_proofs", + "halo2curves", + "num-bigint", + "shielder-circuits" +] \ No newline at end of file diff --git a/crates/shielder-rust-sdk/src/account/call_data.rs b/crates/shielder-rust-sdk/src/account/call_data.rs new file mode 100644 index 00000000..28fbf22f --- /dev/null +++ b/crates/shielder-rust-sdk/src/account/call_data.rs @@ -0,0 +1,271 @@ +use alloy_primitives::{Address, Bytes, U256}; +use rand::rngs::OsRng; +use shielder_circuits::{ + circuits::{Params, ProvingKey}, + consts::{ + merkle_constants::{ARITY, NOTE_TREE_HEIGHT}, + RANGE_PROOF_CHUNK_SIZE, + }, + deposit::DepositProverKnowledge, + new_account::NewAccountProverKnowledge, + withdraw::WithdrawProverKnowledge, + Field, ProverKnowledge, PublicInputProvider, F, +}; + +use super::secrets::id_hiding_nonce; +use crate::{ + account::ShielderAccount, + contract::{ + ShielderContract::{depositNativeCall, newAccountNativeCall, withdrawNativeCall}, + WithdrawCommitment, + }, + conversion::{field_to_u256, u256_to_field}, + version::ContractVersion, +}; + +struct ActionSecrets { + nullifier_old: U256, + trapdoor_old: U256, + nullifier_new: U256, + trapdoor_new: U256, +} + +/// A trait for the different types of calls, for which calldata can be prepared based on the +/// ShielderAccount's state. +pub trait CallType { + /// The extra data that is required for the call. + type Extra; + /// We suppose that every call has a corresponding circuit values struct used to generate a + /// proof. + type ProverKnowledge: ProverKnowledge; + /// The type of the contract call data. + type Calldata; + + /// Prepare the prover knowledge for the call. + fn prepare_prover_knowledge( + account: &ShielderAccount, + amount: U256, + extra: &Self::Extra, + ) -> Self::ProverKnowledge; + + /// Prepare the call data for the contract call. + fn prepare_call_data( + prover_knowledge: &Self::ProverKnowledge, + proof: Vec, + extra: &Self::Extra, + ) -> Self::Calldata; +} + +pub enum NewAccountCallType {} +impl CallType for NewAccountCallType { + type Extra = (); + type ProverKnowledge = NewAccountProverKnowledge; + type Calldata = newAccountNativeCall; + + fn prepare_prover_knowledge( + account: &ShielderAccount, + amount: U256, + _: &Self::Extra, + ) -> Self::ProverKnowledge { + NewAccountProverKnowledge { + id: u256_to_field(account.id), + nullifier: u256_to_field(account.next_nullifier()), + trapdoor: u256_to_field(account.next_trapdoor()), + initial_deposit: u256_to_field(amount), + } + } + + fn prepare_call_data( + prover_knowledge: &Self::ProverKnowledge, + proof: Vec, + _: &Self::Extra, + ) -> Self::Calldata { + use shielder_circuits::circuits::new_account::NewAccountInstance::*; + newAccountNativeCall { + newNote: field_to_u256(prover_knowledge.compute_public_input(HashedNote)), + idHash: field_to_u256(prover_knowledge.compute_public_input(HashedId)), + proof: Bytes::from(proof), + } + } +} + +pub struct MerkleProof { + pub root: U256, + pub path: [[U256; ARITY]; NOTE_TREE_HEIGHT], +} + +pub enum DepositCallType {} +impl CallType for DepositCallType { + type Extra = MerkleProof; + type ProverKnowledge = DepositProverKnowledge; + + type Calldata = depositNativeCall; + + fn prepare_prover_knowledge( + account: &ShielderAccount, + amount: U256, + merkle: &Self::Extra, + ) -> Self::ProverKnowledge { + let ActionSecrets { + nullifier_old, + trapdoor_old, + nullifier_new, + trapdoor_new, + .. + } = account.get_secrets(); + + let nonce = id_hiding_nonce(); + + DepositProverKnowledge { + id: u256_to_field(account.id), + nonce: u256_to_field(nonce), + nullifier_old: u256_to_field(nullifier_old), + trapdoor_old: u256_to_field(trapdoor_old), + account_old_balance: u256_to_field(account.shielded_amount), + path: map_path_to_field(merkle.path), + deposit_value: u256_to_field(amount), + nullifier_new: u256_to_field(nullifier_new), + trapdoor_new: u256_to_field(trapdoor_new), + } + } + + fn prepare_call_data( + pk: &Self::ProverKnowledge, + proof: Vec, + _: &Self::Extra, + ) -> Self::Calldata { + use shielder_circuits::circuits::deposit::DepositInstance::*; + depositNativeCall { + idHiding: field_to_u256(pk.compute_public_input(IdHiding)), + oldNullifierHash: field_to_u256(pk.compute_public_input(HashedOldNullifier)), + newNote: field_to_u256(pk.compute_public_input(HashedNewNote)), + merkleRoot: field_to_u256(pk.compute_public_input(MerkleRoot)), + proof: Bytes::from(proof.to_vec()), + } + } +} + +pub struct WithdrawExtra { + pub merkle_proof: MerkleProof, + pub to: Address, + pub relayer_address: Address, + pub relayer_fee: U256, + pub contract_version: ContractVersion, +} + +pub enum WithdrawCallType {} +impl CallType for WithdrawCallType { + type Extra = WithdrawExtra; + type ProverKnowledge = WithdrawProverKnowledge; + type Calldata = withdrawNativeCall; + + fn prepare_prover_knowledge( + account: &ShielderAccount, + amount: U256, + extra: &Self::Extra, + ) -> Self::ProverKnowledge { + let ActionSecrets { + nullifier_old, + trapdoor_old, + nullifier_new, + trapdoor_new, + .. + } = account.get_secrets(); + + let commitment = WithdrawCommitment { + contract_version: extra.contract_version, + withdraw_address: extra.to, + relayer_address: extra.relayer_address, + relayer_fee: extra.relayer_fee, + } + .commitment_hash(); + let nonce = id_hiding_nonce(); + + WithdrawProverKnowledge::<_, RANGE_PROOF_CHUNK_SIZE> { + id: u256_to_field(account.id), + nonce: u256_to_field(nonce), + nullifier_old: u256_to_field(nullifier_old), + trapdoor_old: u256_to_field(trapdoor_old), + account_old_balance: u256_to_field(account.shielded_amount), + path: map_path_to_field(extra.merkle_proof.path), + withdrawal_value: u256_to_field(amount), + nullifier_new: u256_to_field(nullifier_new), + trapdoor_new: u256_to_field(trapdoor_new), + commitment: u256_to_field(commitment), + } + } + + fn prepare_call_data( + pk: &Self::ProverKnowledge, + proof: Vec, + extra: &Self::Extra, + ) -> Self::Calldata { + use shielder_circuits::circuits::withdraw::WithdrawInstance::*; + withdrawNativeCall { + idHiding: field_to_u256(pk.compute_public_input(IdHiding)), + amount: field_to_u256(pk.compute_public_input(WithdrawalValue)), + withdrawAddress: extra.to, + merkleRoot: field_to_u256(pk.compute_public_input(MerkleRoot)), + oldNullifierHash: field_to_u256(pk.compute_public_input(HashedOldNullifier)), + newNote: field_to_u256(pk.compute_public_input(HashedNewNote)), + proof: Bytes::from(proof), + relayerAddress: extra.relayer_address, + relayerFee: extra.relayer_fee, + } + } +} + +impl ShielderAccount { + pub fn prepare_call( + &self, + params: &Params, + pk: &ProvingKey, + amount: U256, + extra: &CT::Extra, + ) -> CT::Calldata { + let prover_knowledge = CT::prepare_prover_knowledge(self, amount, extra); + let proof = generate_proof(params, pk, &prover_knowledge); + CT::prepare_call_data(&prover_knowledge, proof, extra) + } + + fn get_secrets(&self) -> ActionSecrets { + let nullifier_old = self.previous_nullifier(); + let trapdoor_old = self + .previous_trapdoor() + .expect("The first action cannot refer to a previous trapdoor"); + + let nullifier_new = self.next_nullifier(); + let trapdoor_new = self.next_trapdoor(); + + ActionSecrets { + nullifier_old, + trapdoor_old, + nullifier_new, + trapdoor_new, + } + } +} + +fn generate_proof( + params: &Params, + pk: &ProvingKey, + prover_knowledge: &impl ProverKnowledge, +) -> Vec { + shielder_circuits::generate_proof( + params, + pk, + prover_knowledge.create_circuit(), + &prover_knowledge.serialize_public_input(), + &mut OsRng, + ) +} + +fn map_path_to_field(path: [[U256; ARITY]; NOTE_TREE_HEIGHT]) -> [[F; ARITY]; NOTE_TREE_HEIGHT] { + let mut result = [[F::ZERO; ARITY]; NOTE_TREE_HEIGHT]; + for (i, row) in path.iter().enumerate() { + for (j, element) in row.iter().enumerate() { + result[i][j] = u256_to_field(*element); + } + } + result +} diff --git a/crates/shielder-rust-sdk/src/account/mod.rs b/crates/shielder-rust-sdk/src/account/mod.rs new file mode 100644 index 00000000..3df83765 --- /dev/null +++ b/crates/shielder-rust-sdk/src/account/mod.rs @@ -0,0 +1,129 @@ +use std::fmt::Display; + +use alloy_primitives::U256; +use halo2curves::bn256::Fr; +use serde::{Deserialize, Serialize}; + +#[cfg(feature = "contract")] +pub mod call_data; +pub mod secrets; +mod shielder_action; + +pub use shielder_action::{ShielderAction, ShielderTxData}; +use shielder_circuits::{note_hash, Note}; + +use crate::{ + conversion::{field_to_u256, u256_to_field}, + version::contract_version, +}; + +#[derive(Clone, Eq, Debug, PartialEq, Default, Deserialize, Serialize)] +pub struct ShielderAccount { + /// The seed used to generate nullifiers and trapdoors. The only secret we need to preserve to + /// restore the account. + /// + /// WARNING: You SHOULD NOT use `Self::Default` in production, as this will set the seed to + /// zero, which is insecure and might get in conflict with other accounts (similarly set up). + pub id: U256, + /// The nonce used to generate nullifiers and trapdoors. It is incremented after each action. + pub nonce: u32, + /// The total current amount of tokens shielded by the account. + pub shielded_amount: U256, + /// The history of actions performed by the account. + pub history: Vec, +} + +impl Display for ShielderAccount { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("ShielderAccount") + .field("id", &self.id) + .field("nonce", &self.nonce) + .field("shielded_amount", &self.shielded_amount) + .field("current_leaf_index", &self.current_leaf_index()) + .finish() + } +} + +impl ShielderAccount { + /// Create a new account with the given id. Other fields are initialized to default values + /// (like the account has no history). + /// + /// Note: You SHOULD prefer using `Self::new` instead of `Default::default()`, unless you are + /// writing single-actor tests. + pub fn new(id: U256) -> Self { + Self { + id, + ..Default::default() + } + } + + /// Save the action in the account history and update the account state. + pub fn register_action(&mut self, action: impl Into) { + let action = action.into(); + match &action { + ShielderAction::Deposit(data) | ShielderAction::NewAccount(data) => { + self.shielded_amount = self + .shielded_amount + .checked_add(data.amount) + .expect("shielded amount overflow"); + } + ShielderAction::Withdraw { data, .. } => { + self.shielded_amount = self + .shielded_amount + .checked_sub(data.amount) + .expect("shielded amount underflow"); + } + } + self.nonce += 1; + self.history.push(action); + } + + /// Get the index of the last leaf in the Merkle tree containing the account's note. + pub fn current_leaf_index(&self) -> Option { + self.history.last().map(|action| match action { + ShielderAction::NewAccount(data) + | ShielderAction::Deposit(data) + | ShielderAction::Withdraw { data, .. } => data.note_index, + }) + } + + /// Compute note representing current state. `None` if no operations have been performed. + pub fn note(&self) -> Option { + if self.nonce == 0 { + return None; + } + let raw_note: Fr = note_hash(&Note { + version: contract_version().note_version(), + id: u256_to_field(self.id), + nullifier: u256_to_field(self.previous_nullifier()), + trapdoor: u256_to_field(self.previous_trapdoor().unwrap()), // safe unwrap + account_balance: u256_to_field(self.shielded_amount), + }); + Some(field_to_u256(raw_note)) + } + + /// Generate the nullifier for the next action to be done. + pub fn next_nullifier(&self) -> U256 { + secrets::nullifier(self.id, self.nonce) + } + + /// Generate the nullifier for the previous action. If the account has no actions, `self.id` + /// is used as 'pre-nullifier'. + pub fn previous_nullifier(&self) -> U256 { + self.nonce + .checked_sub(1) + .map_or(self.id, |nonce| secrets::nullifier(self.id, nonce)) + } + + /// Generate the trapdoor for the next action to be done. + pub fn next_trapdoor(&self) -> U256 { + secrets::trapdoor(self.id, self.nonce) + } + + /// Generate the trapdoor for the previous action. If the account has no actions, return `None`. + pub fn previous_trapdoor(&self) -> Option { + self.nonce + .checked_sub(1) + .map(|nonce| secrets::trapdoor(self.id, nonce)) + } +} diff --git a/crates/shielder-rust-sdk/src/account/secrets.rs b/crates/shielder-rust-sdk/src/account/secrets.rs new file mode 100644 index 00000000..772a8f31 --- /dev/null +++ b/crates/shielder-rust-sdk/src/account/secrets.rs @@ -0,0 +1,57 @@ +use alloy_primitives::U256; +use rand::{rngs::OsRng, Rng}; +use sha3::Digest; +use shielder_circuits::consts::NONCE_UPPER_LIMIT; + +const NULLIFIER_LABEL: &[u8] = b"nullifier"; +const TRAPDOOR_LABEL: &[u8] = b"trapdoor"; + +// Copied from `src/bn256/fr.rs` in `halo2curves`. Unfortunately only a string constant is public +// in `halo2curves`, and we need bytes for performance reasons. +const FIELD_MODULUS: U256 = U256::from_limbs([ + 0x43e1f593f0000001, + 0x2833e84879b97091, + 0xb85045b68181585d, + 0x30644e72e131a029, +]); + +/// Returns a pseudorandom field element deterministically computed from `id` and `nonce`. +pub fn nullifier(id: U256, nonce: u32) -> U256 { + hash(id, nonce, NULLIFIER_LABEL) +} + +/// Returns a pseudorandom field element deterministically computed from `id` and `nonce`. +pub fn trapdoor(id: U256, nonce: u32) -> U256 { + hash(id, nonce, TRAPDOOR_LABEL) +} + +fn hash(id: U256, nonce: u32, label: &[u8]) -> U256 { + let mut hasher = sha3::Keccak256::new(); + hasher.update(id.to_be_bytes_vec()); + hasher.update(label); + hasher.update(nonce.to_be_bytes()); + U256::from_be_slice(hasher.finalize().as_slice()).reduce_mod(FIELD_MODULUS) +} + +pub fn id_hiding_nonce() -> U256 { + let mut rng = OsRng; + let nonce = rng.gen_range(0..NONCE_UPPER_LIMIT); + + U256::from(nonce) +} + +#[cfg(test)] +mod tests { + use alloy_primitives::U256; + use halo2curves::{bn256::Fr, ff::PrimeField}; + + use super::FIELD_MODULUS; + + #[test] + pub fn modulus_constant_is_correct() { + assert_eq!( + FIELD_MODULUS, + U256::from_str_radix(Fr::MODULUS.strip_prefix("0x").unwrap(), 16).unwrap() + ); + } +} diff --git a/crates/shielder-rust-sdk/src/account/shielder_action.rs b/crates/shielder-rust-sdk/src/account/shielder_action.rs new file mode 100644 index 00000000..bfaf287e --- /dev/null +++ b/crates/shielder-rust-sdk/src/account/shielder_action.rs @@ -0,0 +1,74 @@ +use alloy_primitives::{Address, TxHash, U256}; +use serde::{Deserialize, Serialize}; + +#[cfg(feature = "contract")] +use crate::contract::ShielderContract::{ + DepositNative, NewAccountNative, ShielderContractEvents, WithdrawNative, +}; + +#[derive(Clone, Eq, PartialEq, Debug, Deserialize, Serialize)] +pub enum ShielderAction { + NewAccount(ShielderTxData), + Deposit(ShielderTxData), + Withdraw { to: Address, data: ShielderTxData }, +} + +#[cfg(feature = "contract")] +impl From<(TxHash, ShielderContractEvents)> for ShielderAction { + fn from((tx_hash, event): (TxHash, ShielderContractEvents)) -> Self { + match event { + ShielderContractEvents::NewAccountNative(NewAccountNative { + amount, + newNoteIndex, + .. + }) => Self::new_account(amount, newNoteIndex, tx_hash), + ShielderContractEvents::DepositNative(DepositNative { + amount, + newNoteIndex, + .. + }) => Self::deposit(amount, newNoteIndex, tx_hash), + ShielderContractEvents::WithdrawNative(WithdrawNative { + amount, + withdrawAddress, + newNoteIndex, + .. + }) => Self::withdraw(amount, newNoteIndex, tx_hash, withdrawAddress), + } + } +} + +impl ShielderAction { + pub fn new_account(amount: U256, note_index: U256, tx_hash: TxHash) -> Self { + Self::NewAccount(ShielderTxData { + amount, + note_index, + tx_hash, + }) + } + + pub fn deposit(amount: U256, note_index: U256, tx_hash: TxHash) -> Self { + Self::Deposit(ShielderTxData { + amount, + note_index, + tx_hash, + }) + } + + pub fn withdraw(amount: U256, note_index: U256, tx_hash: TxHash, to: Address) -> Self { + Self::Withdraw { + to, + data: ShielderTxData { + amount, + note_index, + tx_hash, + }, + } + } +} + +#[derive(Clone, Eq, PartialEq, Debug, Deserialize, Serialize)] +pub struct ShielderTxData { + pub amount: U256, + pub note_index: U256, + pub tx_hash: TxHash, +} diff --git a/crates/shielder-rust-sdk/src/contract/api.rs b/crates/shielder-rust-sdk/src/contract/api.rs new file mode 100644 index 00000000..ea8e0ac7 --- /dev/null +++ b/crates/shielder-rust-sdk/src/contract/api.rs @@ -0,0 +1,85 @@ +use alloy_primitives::{Address, U256}; +use alloy_provider::Provider; +use alloy_sol_types::SolCall; + +use super::ContractResult; +use crate::contract::{ + call_type::CallType, + connection::{Connection, ConnectionPolicy, NoProvider}, + ShielderContract::{ + depositNativeCall, getMerklePathCall, newAccountNativeCall, nullifiersCall, + withdrawNativeCall, + }, +}; + +/// Standard user of the Shielder contract. Can deposit and withdraw funds from the contract, as +/// well as query the contract for information. +/// +/// Essentially, this is a thin wrapper around the `Connection` struct that provides a more +/// user-friendly interface for interacting with the contract. +#[derive(Clone)] +pub struct ShielderUser { + connection: Connection, +} + +impl ShielderUser

{ + /// Create a new `ShielderUser` instance. + pub fn new(contract_address: Address, connection_policy: ConnectionPolicy

) -> Self { + let connection = Connection::new(contract_address, connection_policy); + Self { connection } + } + + /// Get the address of the user. + pub fn address(&self) -> Address { + self.connection.caller_address() + } + + /// Create new account. + pub async fn create_new_account_native>( + &self, + call: newAccountNativeCall, + value: U256, + ) -> ContractResult { + self.connection.call_with_value::(call, value).await + } + + /// Deposit native currency into the contract. + pub async fn deposit_native>( + &self, + call: depositNativeCall, + value: U256, + ) -> ContractResult { + self.connection.call_with_value::(call, value).await + } + + /// Withdraw native currency from the contract. + pub async fn withdraw_native>( + &self, + call: withdrawNativeCall, + ) -> ContractResult { + self.connection.call::(call).await + } + + /// Get the block number for the `nullifierHash`. `0` means that the nullifier hasn't been used + /// yet. + pub async fn nullifiers>( + &self, + nullifier_hash: U256, + ) -> ContractResult { + self.connection + .call::(nullifiersCall { + nullifierHash: nullifier_hash, + }) + .await + } + + /// Get the Merkle path for a given ID. + pub async fn get_merkle_path>( + &self, + id: U256, + ) -> ContractResult { + self.connection + .call::(getMerklePathCall::new((id,))) + .await + } +} diff --git a/crates/shielder-rust-sdk/src/contract/call_type.rs b/crates/shielder-rust-sdk/src/contract/call_type.rs new file mode 100644 index 00000000..1499c05c --- /dev/null +++ b/crates/shielder-rust-sdk/src/contract/call_type.rs @@ -0,0 +1,67 @@ +use std::marker::PhantomData; + +use alloy_contract::CallBuilder; +use alloy_primitives::{BlockHash, TxHash}; +use alloy_provider::Provider; +use alloy_transport::Transport; + +use crate::contract::{ContractResult, ShielderContractCall, ShielderContractError}; + +/// Submit the transaction to the network and wait for the block inclusion. +pub struct Call; +/// Submit the transaction to the network. +pub struct Submit; +/// Dry-run the transaction. +pub struct DryRun; + +pub trait CallType { + type Result: Send + Sync; + + fn action>( + call_builder: CallBuilder>, + ) -> impl std::future::Future> + Send; +} + +impl CallType for Call { + type Result = (TxHash, BlockHash); + + async fn action>( + call_builder: CallBuilder>, + ) -> ContractResult { + call_builder + .send() + .await? + .get_receipt() + .await + .map_err(|e| { + eprintln!("Couldn't track the transaction: {e:?}"); + ShielderContractError::WatchError + }) + .map(|receipt| { + ( + receipt.transaction_hash, + receipt.block_hash.expect("Block hash is missing"), + ) + }) + } +} + +impl CallType for Submit { + type Result = TxHash; + + async fn action>( + call_builder: CallBuilder>, + ) -> ContractResult { + Ok(*call_builder.send().await?.tx_hash()) + } +} + +impl CallType for DryRun { + type Result = C::UnwrappedResult; + + async fn action>( + call_builder: CallBuilder>, + ) -> ContractResult { + Ok(call_builder.call().await.map(C::unwrap_result)?) + } +} diff --git a/crates/shielder-rust-sdk/src/contract/connection.rs b/crates/shielder-rust-sdk/src/contract/connection.rs new file mode 100644 index 00000000..8fecfeff --- /dev/null +++ b/crates/shielder-rust-sdk/src/contract/connection.rs @@ -0,0 +1,125 @@ +use std::marker::PhantomData; + +use alloy_contract::CallDecoder; +use alloy_network::Ethereum; +use alloy_primitives::{Address, U256}; +use alloy_provider::{Provider, RootProvider}; +use alloy_signer_local::PrivateKeySigner; +use alloy_transport::BoxTransport; + +use crate::contract::{ + call_type::CallType, providers::create_provider_with_signer, ContractResult, ShielderContract, + ShielderContractCall, +}; + +/// Placeholder for a provider in `ConnectionPolicy` / `Connection` and `ShielderUser` when only +/// `ConnectionPolicy::OnDemand` variant is used. +#[derive(Clone)] +pub enum NoProvider {} +impl Provider for NoProvider { + fn root(&self) -> &RootProvider { + unreachable!("NoProvider does not have a root provider") + } +} + +#[derive(Clone)] +pub enum ConnectionPolicy { + Keep { + provider: Provider, + caller_address: Address, + }, + OnDemand { + rpc_url: String, + signer: PrivateKeySigner, + }, +} + +impl ConnectionPolicy

{ + pub fn caller_address(&self) -> Address { + match self { + ConnectionPolicy::Keep { caller_address, .. } => *caller_address, + ConnectionPolicy::OnDemand { signer, .. } => signer.address(), + } + } +} + +#[derive(Clone)] +pub struct Connection { + contract_address: Address, + policy: ConnectionPolicy, +} + +// We require `Provider` to be `Clone`. Otherwise it is extremely hard to satisfy `Send` bounds in +// the async environment (a lot of "`Send` would have to be implemented for the type +// `&Provider`"-like errors happen). +impl Connection

{ + pub fn new(contract_address: Address, policy: ConnectionPolicy

) -> Self { + Self { + contract_address, + policy, + } + } + + pub fn caller_address(&self) -> Address { + self.policy.caller_address() + } + + pub async fn call, Call: ShielderContractCall + Unpin>( + &self, + call: Call, + ) -> ContractResult + where + PhantomData: CallDecoder + Unpin, + { + self._call::(call, None).await + } + + pub async fn call_with_value, Call: ShielderContractCall + Unpin>( + &self, + call: Call, + value: U256, + ) -> ContractResult + where + PhantomData: CallDecoder + Unpin, + { + self._call::(call, Some(value)).await + } + + async fn _call, Call: ShielderContractCall + Unpin>( + &self, + call: Call, + value: Option, + ) -> ContractResult + where + PhantomData: CallDecoder + Unpin, + { + match &self.policy { + ConnectionPolicy::Keep { provider, .. } => { + self.call_with_resolved_provider::(call, value, provider.clone()) + .await + } + ConnectionPolicy::OnDemand { rpc_url, signer } => { + let provider = create_provider_with_signer(rpc_url, signer.clone()).await?; + self.call_with_resolved_provider::(call, value, provider) + .await + } + } + } + + async fn call_with_resolved_provider, Call: ShielderContractCall + Unpin>( + &self, + call: Call, + value: Option, + provider: impl Provider, + ) -> ContractResult + where + PhantomData: CallDecoder + Unpin, + { + let contract = ShielderContract::new(self.contract_address, provider); + let call_builder = contract + .call_builder(&call) + .from(self.caller_address()) + .value(value.unwrap_or_default()); + CT::action(call_builder).await + } +} diff --git a/crates/shielder-rust-sdk/src/contract/events.rs b/crates/shielder-rust-sdk/src/contract/events.rs new file mode 100644 index 00000000..1bc32c56 --- /dev/null +++ b/crates/shielder-rust-sdk/src/contract/events.rs @@ -0,0 +1,26 @@ +use alloy_primitives::{BlockHash, TxHash}; +use alloy_provider::Provider; +use alloy_rpc_types::Filter; +use alloy_sol_types::SolEvent; + +use crate::contract::{ContractResult, ShielderContractError}; + +/// Look at the logs of `tx_hash` in `block_hash` and return the first event of type `Event`. +pub async fn get_event( + provider: &impl Provider, + tx_hash: TxHash, + block_hash: BlockHash, +) -> ContractResult { + let filter = Filter::new().at_block_hash(block_hash); + let log_data = provider + .get_logs(&filter) + .await + .map_err(ShielderContractError::ProviderError)? + .iter() + .find(|log| log.transaction_hash == Some(tx_hash)) + .ok_or(ShielderContractError::EventNotFound)? + .data() + .clone(); + + Event::decode_log_data(&log_data, true).map_err(|_| ShielderContractError::EventNotFound) +} diff --git a/crates/shielder-rust-sdk/src/contract/merkle_path.rs b/crates/shielder-rust-sdk/src/contract/merkle_path.rs new file mode 100644 index 00000000..fa1f93c4 --- /dev/null +++ b/crates/shielder-rust-sdk/src/contract/merkle_path.rs @@ -0,0 +1,38 @@ +use alloy_primitives::U256; + +use crate::{ + consts::{ARITY, TREE_HEIGHT}, + contract::{call_type::DryRun, ContractResult, ShielderUser}, +}; + +/// Query the contract for the current merkle path to the leaf at `leaf_index`. Translate the +/// response to a structured format over the field type `F`. +pub async fn get_current_merkle_path( + leaf_index: U256, + shielder_user: &ShielderUser, +) -> ContractResult<(U256, [[U256; ARITY]; TREE_HEIGHT])> { + let flat_merkle_path = shielder_user.get_merkle_path::(leaf_index).await?; + reorganize_merkle_path(flat_merkle_path) +} + +/// Reorganize a flattened merkle path into a 2D array and a root element. +fn reorganize_merkle_path( + merkle_path: Vec, +) -> ContractResult<(U256, [[U256; ARITY]; TREE_HEIGHT])> { + if merkle_path.len() != ARITY * TREE_HEIGHT + 1 { + return Err("Invalid merkle path length".into()); + } + + let root = *merkle_path.last().expect("Empty merkle path"); + + let mut result = [[U256::ZERO; ARITY]; TREE_HEIGHT]; + for (i, element) in merkle_path + .into_iter() + .enumerate() + .take(ARITY * TREE_HEIGHT) + { + result[i / ARITY][i % ARITY] = element; + } + + Ok((root, result)) +} diff --git a/crates/shielder-rust-sdk/src/contract/mod.rs b/crates/shielder-rust-sdk/src/contract/mod.rs new file mode 100644 index 00000000..cf9ffc35 --- /dev/null +++ b/crates/shielder-rust-sdk/src/contract/mod.rs @@ -0,0 +1,132 @@ +use alloy_contract::Error; +use alloy_primitives::{keccak256, Address, TxHash, U256}; +use alloy_signer_local::LocalSignerError; +use alloy_sol_types::SolValue; +use alloy_transport::TransportError; +pub use api::ShielderUser; +pub use connection::ConnectionPolicy; +pub use types::*; + +use crate::{conversion::address_to_u256, version::ContractVersion}; + +mod api; +pub mod call_type; +mod connection; +pub mod events; +pub mod merkle_path; +pub mod providers; +mod types; + +/// Errors that can occur when interacting with the Shielder contract. +#[allow(missing_docs)] +#[derive(Debug, thiserror::Error)] +pub enum ShielderContractError { + #[error("Couldn't create connection: {0:?}")] + ProviderError(TransportError), + #[error("Call failed due to invalid nonce. Probably the signer has just been used in parallel. Please retry.")] + SignerConflict, + #[error("Call failed: {0:?}")] + CallError(Error), + #[error("Couldn't track the transaction")] + WatchError, + #[error("Event was not found for the provided transaction coordinates")] + EventNotFound, + #[error("Invalid signer: {0:?}")] + InvalidSigner(LocalSignerError), + #[error("Other error: {0}")] + Other(String), +} + +impl From for ShielderContractError { + fn from(e: Error) -> Self { + let e_str = e.to_string(); + if e_str.contains("nonce too low") + || e_str.contains("transaction already imported") + || e_str.contains("already known") + { + ShielderContractError::SignerConflict + } else { + ShielderContractError::CallError(e) + } + } +} + +impl From<&str> for ShielderContractError { + fn from(e: &str) -> Self { + ShielderContractError::Other(e.to_string()) + } +} + +type ContractResult = Result; +/// Result type for Shielder contract call operations. Contains the transaction hash of the call. +pub type ContractCallResult = ContractResult; +/// Result type for Shielder contract dry run operations. Contains the result of the operation. +pub type ContractDryRunResult = ContractResult; + +pub struct WithdrawCommitment { + pub contract_version: ContractVersion, + pub withdraw_address: Address, + pub relayer_address: Address, + pub relayer_fee: U256, +} + +impl WithdrawCommitment { + pub fn commitment_hash(&self) -> U256 { + // Same order as in contract + let hash: U256 = keccak256( + ( + self.contract_version.to_bytes(), + address_to_u256(self.withdraw_address), + address_to_u256(self.relayer_address), + self.relayer_fee, + ) + .abi_encode_packed(), + ) + .into(); + + // shifting right by 4 bits, same as in the contract + hash >> 4 + } +} + +#[cfg(test)] +mod tests { + use std::str::FromStr; + + use alloy_primitives::{Address, U256}; + use halo2curves::ff::PrimeField; + use rand::{thread_rng, Rng}; + + use crate::{contract::WithdrawCommitment, version::ContractVersion}; + + fn sample_commitment() -> WithdrawCommitment { + let mut rng = thread_rng(); + WithdrawCommitment { + contract_version: ContractVersion { + note_version: rng.gen(), + circuit_version: rng.gen(), + patch_version: rng.gen(), + }, + + withdraw_address: Address::random(), + relayer_address: Address::random(), + relayer_fee: rng.gen(), + } + } + + #[test] + fn test_commitment_hash_fit_into_field() { + const NUMBER_TESTS: usize = 1_000; + let r = U256::from_str(halo2curves::bn256::Fr::MODULUS).unwrap(); + + for _ in 0..NUMBER_TESTS { + let random_commitment = sample_commitment().commitment_hash(); + assert!( + random_commitment < r, + "Failed inequality `{:?}` < `{:?}`", + random_commitment, + r + ); + } + } +} diff --git a/crates/shielder-rust-sdk/src/contract/providers.rs b/crates/shielder-rust-sdk/src/contract/providers.rs new file mode 100644 index 00000000..353417cb --- /dev/null +++ b/crates/shielder-rust-sdk/src/contract/providers.rs @@ -0,0 +1,104 @@ +use std::sync::Arc; + +use alloy_network::{Ethereum, EthereumWallet, Network}; +use alloy_provider::{ + fillers::{ + BlobGasFiller, CachedNonceManager, ChainIdFiller, FillerControlFlow, GasFiller, + NonceFiller, TxFiller, WalletFiller, + }, + Provider, ProviderBuilder, SendableTx, +}; +use alloy_signer_local::PrivateKeySigner; +use alloy_transport::{Transport, TransportResult}; + +use crate::contract::{ContractResult, ShielderContractError}; + +/// Creates a provider for the given RPC URL. This is a simple provider, without any fillers or +/// signer configuration (apart from some devnet-specific defaults). It is suitable for doing +/// read-only operations. +pub async fn create_simple_provider(rpc_url: &str) -> ContractResult { + ProviderBuilder::new() + .on_builtin(rpc_url) + .await + .map_err(ShielderContractError::ProviderError) +} + +/// Creates a provider for the given RPC URL, with the given signer. This provider is suitable for +/// doing write operations, as it will sign transactions with the given signer. +/// +/// Note: The signer will fetch the nonce before every transaction. Use this if the same signer +/// might be used from multiple places (although bare in mind that nonce conflicts might still +/// occur). +pub async fn create_provider_with_signer( + rpc_url: &str, + signer: PrivateKeySigner, +) -> ContractResult { + ProviderBuilder::new() + .with_recommended_fillers() + .filler(WalletFiller::new(EthereumWallet::from(signer))) + .on_builtin(rpc_url) + .await + .map_err(ShielderContractError::ProviderError) +} + +/// Creates a provider for the given RPC URL, with the given signer. This provider is suitable for +/// doing write operations, as it will sign transactions with the given signer. +/// +/// Note: The signer will locally track the nonce and cache it. Use this if the signer is only used +/// from one place. +pub async fn create_provider_with_nonce_caching_signer( + rpc_url: &str, + signer: PrivateKeySigner, +) -> ContractResult { + ProviderBuilder::new() + // The four fillers below are the recommended fillers are the same as + // `with_recommended_fillers` except the `NonceManager` parameter for `NonceFiller`. + .filler(GasFiller) + .filler(BlobGasFiller) + .filler(NonceFiller::::default()) + .filler(ChainIdFiller::default()) + .filler(WalletFiller::new(EthereumWallet::from(signer))) + .filler(LoggingFiller::default()) + .on_builtin(rpc_url) + .await + .map_err(ShielderContractError::ProviderError) + .map(Arc::new) +} + +/// A noop filler that reports transaction details once it is prepared, just before sending. For +/// debugging purposes. +#[derive(Copy, Clone, Debug, Default)] +pub struct LoggingFiller {} + +impl TxFiller for LoggingFiller { + type Fillable = (); + + fn status(&self, _tx: &::TransactionRequest) -> FillerControlFlow { + FillerControlFlow::Finished + } + + fn fill_sync(&self, tx: &mut SendableTx) { + match tx { + SendableTx::Builder(tx) => { + tracing::info!(sender = ?tx.from, to = ?tx.to, nonce = tx.nonce, "Sending a transaction"); + } + SendableTx::Envelope(_) => {} // We don't use envelopes in this crate. + } + } + + async fn prepare, T: Transport + Clone>( + &self, + _provider: &P, + _tx: &::TransactionRequest, + ) -> TransportResult { + Ok(()) + } + + async fn fill( + &self, + _fillable: Self::Fillable, + tx: SendableTx, + ) -> TransportResult> { + Ok(tx) + } +} diff --git a/crates/shielder-rust-sdk/src/contract/types.rs b/crates/shielder-rust-sdk/src/contract/types.rs new file mode 100644 index 00000000..a9671113 --- /dev/null +++ b/crates/shielder-rust-sdk/src/contract/types.rs @@ -0,0 +1,169 @@ +#![allow(clippy::too_many_arguments)] + +use core::marker::PhantomData; +use std::fmt::Debug; + +use alloy_contract::CallDecoder; +use alloy_primitives::U256; +use alloy_sol_types::{sol, SolCall}; +use ShielderContract::*; + +sol! { + #[sol(rpc, all_derives = true)] + #[derive(Debug, PartialEq, Eq)] + contract ShielderContract { + event NewAccountNative(uint256 idHash, uint256 amount, uint256 newNote, uint256 newNoteIndex); + event DepositNative(uint256 idHiding, uint256 amount, uint256 newNote, uint256 newNoteIndex); + event WithdrawNative( + uint256 idHiding, + uint256 amount, + address withdrawAddress, + uint256 newNote, + uint256 newNoteIndex, + address relayerAddress, + uint256 fee, + ); + + error DepositVerificationFailed(); + error DuplicatedNullifier(); + error FeeHigherThanAmount(); + error MerkleRootDoesNotExist(); + error NativeTransferFailed(); + error WithdrawVerificationFailed(); + error NewAccountVerificationFailed(); + error ZeroAmount(); + error AmountOverDepositLimit(); + error AmountTooHigh(); + error ContractBalanceLimitReached(); + error LeafIsNotInTheTree(); + error PrecompileCallFailed(); + + function depositLimit() external view returns (uint256); + + function initialize( + address initialOwner, + address _newAccountVerifier, + address _depositVerifier, + address _withdrawVerifier, + address _newAccountVerifyingKey, + address _depositVerifyingKey, + address _withdrawVerifyingKey, + uint256 _depositLimit + ) public; + + function nullifiers(uint256 nullifierHash) public view returns (uint256); + + function pause() external; + function unpause() external; + + function newAccountNative(uint256 newNote, uint256 idHash, bytes calldata proof) external payable; + function depositNative( + uint256 idHiding, + uint256 oldNullifierHash, + uint256 newNote, + uint256 merkleRoot, + bytes calldata proof, + ) external payable; + function withdrawNative( + uint256 idHiding, + uint256 amount, + address withdrawAddress, + uint256 merkleRoot, + uint256 oldNullifierHash, + uint256 newNote, + bytes calldata proof, + address relayerAddress, + uint256 relayerFee, + ) external; + + function newAccountToken( + address tokenOwner, + address token, + uint256 amount, + uint256 nonce, + uint256 deadline, + bytes calldata signature + ) external; + + function depositToken( + address tokenOwner, + address token, + uint256 amount, + uint256 nonce, + uint256 deadline, + bytes calldata signature + ) external; + + function withdrawToken( + address token, + uint256 amount, + address withdrawAddress, + address relayerAddress, + uint256 relayerFee + ) external; + + function getMerklePath(uint256 id) external view returns (uint256[] memory); + + function setDepositLimit(uint256 _depositLimit) external; + } +} + +impl ShielderContractEvents { + pub fn note(&self) -> U256 { + match self { + Self::NewAccountNative(NewAccountNative { newNote: note, .. }) + | Self::DepositNative(DepositNative { newNote: note, .. }) + | Self::WithdrawNative(WithdrawNative { newNote: note, .. }) => *note, + } + } +} + +// This is a workaround for the lack of support for `#[derive(Clone)]` in `sol!` macro. +impl Clone for ShielderContractEvents { + fn clone(&self) -> Self { + match self { + Self::NewAccountNative(event) => Self::NewAccountNative(event.clone()), + Self::DepositNative(event) => Self::DepositNative(event.clone()), + Self::WithdrawNative(event) => Self::WithdrawNative(event.clone()), + } + } +} + +pub trait ShielderContractCall: SolCall + Send + Sync { + type UnwrappedResult: Send + Sync; + fn unwrap_result(out: as CallDecoder>::CallOutput) -> Self::UnwrappedResult; +} + +macro_rules! impl_unit_call { + ($call:ident) => { + impl ShielderContractCall for $call { + type UnwrappedResult = (); + + fn unwrap_result( + _: as CallDecoder>::CallOutput, + ) -> Self::UnwrappedResult { + } + } + }; +} + +impl_unit_call!(pauseCall); +impl_unit_call!(unpauseCall); + +impl_unit_call!(newAccountNativeCall); +impl_unit_call!(depositNativeCall); +impl_unit_call!(withdrawNativeCall); + +impl ShielderContractCall for getMerklePathCall { + type UnwrappedResult = Vec; + fn unwrap_result(path: getMerklePathReturn) -> Self::UnwrappedResult { + path._0 + } +} + +impl ShielderContractCall for nullifiersCall { + type UnwrappedResult = U256; + fn unwrap_result(nullifier: nullifiersReturn) -> Self::UnwrappedResult { + nullifier._0 + } +} diff --git a/crates/shielder-rust-sdk/src/lib.rs b/crates/shielder-rust-sdk/src/lib.rs new file mode 100644 index 00000000..87502202 --- /dev/null +++ b/crates/shielder-rust-sdk/src/lib.rs @@ -0,0 +1,310 @@ +//! Rust SDK for zkOS Shielder contract. + +#[cfg(any(feature = "account", feature = "contract", feature = "conversion"))] +pub use alloy_primitives; + +#[cfg(any(feature = "account", feature = "contract", feature = "conversion"))] +pub mod version { + use alloy_primitives::FixedBytes; + #[cfg(feature = "account")] + use shielder_circuits::NoteVersion; + + /// The contract version. + /// Versioned by note, circuit and patch version. + #[derive(Clone, Copy)] + pub struct ContractVersion { + pub note_version: u8, + pub circuit_version: u8, + pub patch_version: u8, + } + + impl ContractVersion { + pub fn to_bytes(&self) -> FixedBytes<3> { + FixedBytes([self.note_version, self.circuit_version, self.patch_version]) + } + + #[cfg(feature = "account")] + pub fn note_version(&self) -> NoteVersion { + NoteVersion::new(self.note_version) + } + } + + /// The contract version. Currently set to 0.0.1 + pub const fn contract_version() -> ContractVersion { + ContractVersion { + note_version: 0, + circuit_version: 0, + patch_version: 1, + } + } +} + +pub mod consts { + pub const ARITY: usize = 7; + pub const TREE_HEIGHT: usize = 13; + + // Not importing the constants directly to avoid depending on `shielder-circuits` for every + // feature. + #[cfg(feature = "account")] + static_assertions::const_assert_eq!(ARITY, shielder_circuits::consts::merkle_constants::ARITY); + #[cfg(feature = "account")] + static_assertions::const_assert_eq!( + TREE_HEIGHT, + shielder_circuits::consts::merkle_constants::NOTE_TREE_HEIGHT + ); +} + +/// Utilities for interacting with the Shielder contract. +#[cfg(feature = "contract")] +pub mod contract; + +/// Utilities for reading in Perpetual Powers of Tau (.ptau) files. +#[cfg(feature = "powers_of_tau")] +pub mod powers_of_tau; + +/// Utilities for interacting with the Permit2 contract. +#[cfg(feature = "permit2")] +pub mod permit2; + +/// Local shielder account management. +#[cfg(feature = "account")] +pub mod account; + +#[cfg(feature = "native_token")] +pub mod native_token { + pub const NATIVE_TOKEN_DECIMALS: u8 = 18; + pub const ONE_TZERO: u128 = 1_000_000_000_000_000_000; +} + +#[cfg(feature = "parameter_generation")] +pub mod parameter_generation { + use rand::{rngs::SmallRng, RngCore, SeedableRng}; + + pub const DEFAULT_SEED: u64 = 42; + + /// A seeded random number generator that MUST be used for any parameter / key generation in any + /// development context. + /// + /// WARNING: Using another RNG will result in different parameters and keys being generated, + /// which might result in incorrect proofs or failed verification. + /// + /// WARNING: You SHOULD NOT use this function multiple times - otherwise you will get the same + /// values in different contexts. + pub fn rng() -> impl SeedableRng + RngCore { + let key = "SHIELDER_RNG_SEED"; + SmallRng::seed_from_u64( + std::env::var(key) + .ok() + .and_then(|val| val.parse::().ok()) + .unwrap_or_else(|| { + println!("WARNING: using a default value seed for generating the SRS string"); + DEFAULT_SEED + }), + ) + } +} + +/// Type conversion utilities. +/// +/// Contains conversions between: +/// - field element and U256 (both ways): [u256_to_field], [field_to_u256]; +/// - field element and raw bytes (both ways): [bytes_to_field], [field_to_bytes]; +/// - hex-encoded private key and field element: [private_key_to_field]; +/// - raw bytes and U256 (both ways): [bytes_to_u256], [u256_to_bytes]; +/// - Ethereum address and field element (both ways): [address_to_field], [field_to_address]. +/// - Ethereum address and U256: [address_to_u256]. +#[cfg(feature = "conversion")] +pub mod conversion { + use core::result; + use std::{borrow::Borrow, str::FromStr}; + + use alloy_primitives::{Address, U256}; + use halo2curves::ff::PrimeField; + + #[derive(Clone, Debug, PartialEq, Eq, thiserror::Error)] + pub enum Error { + #[error("incorrect vec length: expected {expected}, got {actual}")] + IncorrectVecLength { expected: usize, actual: usize }, + + #[error("halo2 failed to create field element")] + Halo2FieldElementCreationFailed, + + #[error("failed to parse hex string to U256")] + HexU256ParseError, + } + + pub type Result = result::Result; + + /// Convert a U256 value to a field element. + pub fn u256_to_field>(value: impl Borrow) -> F { + F::from(*value.borrow().as_limbs()) + } + + /// Convert a field element to a U256 value. + pub fn field_to_u256, const BYTE_LENGTH: usize>( + value: impl Borrow, + ) -> U256 { + U256::from_le_bytes(value.borrow().to_repr()) + } + + /// Convert raw bytes to an array of a fixed length. + fn byte_vec_to_array(bytes: Vec) -> Result<[u8; LENGTH]> { + let bytes_len = bytes.len(); + match bytes.try_into() { + Ok(bytes) => Ok(bytes), + Err(_) => Err(Error::IncorrectVecLength { + expected: LENGTH, + actual: bytes_len, + }), + } + } + + /// Convert raw bytes to a field element. + pub fn bytes_to_field, const BYTE_LENGTH: usize>( + bytes: Vec, + ) -> Result { + match F::from_repr(byte_vec_to_array::(bytes)?).into() /* conversion from `CtOption` */ { + Some(field_element) => Ok(field_element), + None => Err(Error::Halo2FieldElementCreationFailed), + } + } + + /// Convert a field element to raw bytes. + pub fn field_to_bytes, const BYTE_LENGTH: usize>( + value: F, + ) -> Vec { + value.to_repr().to_vec() + } + + /// Since the private key is an arbitrary 32-byte number, this is a non-reversible mapping. + pub fn private_key_to_field>(hex: &str) -> Result { + let u256 = match U256::from_str(hex) { + Ok(u256) => u256, + Err(_) => return Err(Error::HexU256ParseError), + }; + Ok(u256_to_field(u256)) + } + + /// Convert raw bytes to a U256 value. + pub fn bytes_to_u256(bytes: Vec) -> Result { + Ok(U256::from_le_bytes(byte_vec_to_array::<32>(bytes)?)) + } + + /// Convert a U256 value to raw bytes. + pub fn u256_to_bytes(value: U256) -> Vec { + value.to_le_bytes_vec() + } + + /// Converts an Ethereum address to a field element. MUST be consistent with the Solidity + /// implementation, which is `uint256(uint160(address))`. + pub fn address_to_field>(address: Address) -> F { + let mut bytes = [0u8; 32]; + bytes[12..].copy_from_slice(address.as_slice()); + let u256 = U256::from_be_bytes(bytes); + u256_to_field(u256) + } + + /// Converts a field element to an Ethereum address. MUST be consistent with the method above. + pub fn field_to_address, const BYTE_LENGTH: usize>( + address: F, + ) -> Address { + let mut bytes = address.to_repr(); + bytes.reverse(); + let mut address = [0u8; 20]; + address.copy_from_slice(&bytes[12..]); + Address::from(address) + } + + /// Converts ethereum address into uint256. + pub fn address_to_u256(address: Address) -> U256 { + address.into_word().into() + } + + #[cfg(test)] + mod tests { + use alloy_primitives::{address, U256}; + use halo2curves::bn256::Fr; + + use super::*; + + #[test] + fn between_field_and_u256() { + let u256 = U256::from(41); + let field = Fr::from(41); + + // Check that the conversion functions work both ways. + assert_eq!(u256_to_field::(u256), field); + assert_eq!(field_to_u256(field), u256); + + // Check that the conversion functions are inverses of each other. + assert_eq!(field_to_u256(u256_to_field::(u256)), u256); + assert_eq!(u256_to_field::(field_to_u256(field)), field); + } + + #[test] + fn between_field_and_bytes() { + let bytes = bytes_for_41(); + let field = Fr::from(41); + + // Check that the conversion functions work both ways. + assert_eq!(bytes_to_field(bytes.clone()), Ok(field)); + assert_eq!(field_to_bytes(field), bytes); + + // Check that the conversion functions are inverses of each other. + assert_eq!( + field_to_bytes(bytes_to_field::(bytes.clone()).unwrap()), + bytes + ); + assert_eq!(bytes_to_field(field_to_bytes(field)), Ok(field)); + } + + #[test] + fn from_private_key_to_field() { + let hex = "0x0000000000000000000000000000000000000000000000000000000000000029"; + let field = Fr::from(41); + assert_eq!(private_key_to_field::(hex), Ok(field)); + } + + #[test] + fn between_bytes_and_u256() { + let bytes = bytes_for_41(); + let u256 = U256::from(41); + + // Check that the conversion functions work both ways. + assert_eq!(bytes_to_u256(bytes.clone()), Ok(u256)); + assert_eq!(u256_to_bytes(u256), bytes); + + // Check that the conversion functions are inverses of each other. + assert_eq!(u256_to_bytes(bytes_to_u256(bytes.clone()).unwrap()), bytes); + assert_eq!(bytes_to_u256(u256_to_bytes(u256)), Ok(u256)); + } + + #[test] + fn between_address_and_field() { + let address = address!("0000000000000000000000000000000000000029"); + let field = Fr::from(41); + + // Check that the conversion functions work both ways. + assert_eq!(address_to_field::(address), field); + assert_eq!(field_to_address(field), address); + + // Check that the conversion functions are inverses of each other. + assert_eq!(field_to_address(address_to_field::(address)), address); + assert_eq!(address_to_field::(field_to_address(field)), field); + } + + #[test] + fn convert_address_to_u256() { + let address = address!("0000000000000000000000000000000000000029"); + let val = U256::from(41); + + assert_eq!(address_to_u256(address), val); + } + + fn bytes_for_41() -> Vec { + let mut bytes = [0u8; 32]; + bytes[0] = 41u8; + bytes.to_vec() + } + } +} diff --git a/crates/shielder-rust-sdk/src/permit2.rs b/crates/shielder-rust-sdk/src/permit2.rs new file mode 100644 index 00000000..22195cc3 --- /dev/null +++ b/crates/shielder-rust-sdk/src/permit2.rs @@ -0,0 +1,275 @@ +use alloy_primitives::{keccak256, Address, U256}; +use alloy_sol_types::{sol, Eip712Domain, SolStruct, SolValue}; +use secp256k1::Secp256k1; + +sol! { + #[derive(Debug)] + struct TokenPermissions { + address token; + uint256 amount; + } + + #[derive(Debug)] + struct PermitTransferFrom { + TokenPermissions permitted; + address spender; + uint256 nonce; + uint256 deadline; + } + +} + +/// Calculates the Permit2 EIP712 domain separator off-chain +pub fn get_domain_separator(chain_id: U256, permit2: Address) -> [u8; 32] { + Eip712Domain { + name: Some(String::from("Permit2").into()), + version: None, + chain_id: Some(chain_id), + verifying_contract: Some(permit2), + salt: None, + } + .hash_struct() + .into() +} + +fn hash_token_permissions(permitted: &TokenPermissions) -> [u8; 32] { + keccak256( + ( + permitted.eip712_type_hash(), + permitted.token, + permitted.amount, + ) + .abi_encode(), + ) + .into() +} + +fn hash_permit_transfer_from( + permit: &PermitTransferFrom, + token_permissions_hash: &[u8; 32], +) -> [u8; 32] { + keccak256( + ( + permit.eip712_type_hash(), + token_permissions_hash, + permit.spender, + permit.nonce, + permit.deadline, + ) + .abi_encode(), + ) + .into() +} + +/// EIP712 hash of a Permit2 SignatureTransfer +pub fn get_eip712_hash(permit: &PermitTransferFrom, domain_separator: &[u8; 32]) -> [u8; 32] { + keccak256( + ( + "\x19\x01", + domain_separator, + hash_permit_transfer_from(permit, &hash_token_permissions(&permit.permitted)), + ) + .abi_encode_packed(), + ) + .into() +} + +/// ECDSA signature of a message using SECP256k1 +/// Enable `eip_155` feature to return a signature conforming to the EIP-155 +/// +/// @return (r,s,v) +pub fn sign_message( + message: &[u8], + private_key: &[u8; 32], + #[cfg(feature = "eip_155")] chain_id: u8, +) -> ([u8; 32], [u8; 32], u8) { + let message = secp256k1::Message::from_digest_slice(message).expect("32 bytes message"); + let secret_key = secp256k1::SecretKey::from_slice(private_key).expect("32 bytes private key"); + let secp = Secp256k1::new(); + let signature = secp.sign_ecdsa_recoverable(&message, &secret_key); + + let (recovery_id, bytes) = signature.serialize_compact(); + + let (r, s) = bytes.split_at(32); + + let mut r_arr = [0u8; 32]; + let mut s_arr = [0u8; 32]; + r_arr.copy_from_slice(r); + s_arr.copy_from_slice(s); + + // Compute v value, conditionally with or without EIP-155 + #[cfg(feature = "eip_155")] + let v = recovery_id.to_i32() as u8 + chain_id * 2 + 35; + + #[cfg(not(feature = "eip_155"))] + let v = recovery_id.to_i32() as u8 + 27; + + (r_arr, s_arr, v) +} + +/// Takes in a hex string of an ethereum private key and returns a byte array representation +pub fn destringify_private_key(private_key_str: &str) -> [u8; 32] { + let mut private_key = [0u8; 32]; + // removes 0x prefix + // let hex_string = &private_key_str[2..]; + let hex_string = &private_key_str.strip_prefix("0x").expect("0x prefixed key"); + assert!( + hex_string.len() == 64, + "Private key in hex must be exactly 64 characters long." + ); + for (i, byte) in private_key.iter_mut().enumerate() { + let byte_str = &hex_string[i * 2..i * 2 + 2]; + *byte = u8::from_str_radix(byte_str, 16).expect("Failed to parse string as byte"); + } + + private_key +} + +#[cfg(test)] +mod tests { + + use std::str::FromStr; + + use alloy_primitives::{Address, U256}; + use lazy_static::lazy_static; + + use crate::permit2::{ + get_domain_separator, get_eip712_hash, hash_permit_transfer_from, hash_token_permissions, + PermitTransferFrom, TokenPermissions, + }; + + lazy_static! { + static ref CHAIN_ID: U256 = U256::from(1); + static ref PERMIT2: Address = + Address::from_str("0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512") + .expect("not an address"); + static ref TOKEN: Address = Address::from_str("0x5FbDB2315678afecb367f032d93F642f64180aa3") + .expect("not an address"); + static ref AMOUNT: U256 = U256::from(1); + static ref NONCE: U256 = U256::from(0); + static ref DEADLINE: U256 = U256::from(1); + static ref SPENDER: Address = + Address::from_str("0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0") + .expect("not an address"); + } + + #[test] + fn domain_separator() { + let expected: [u8; 32] = + hex::decode("3dbc46e500c49caeaaffcdb7007378a15d50e34be37f797e13d492807c0c697b") + .expect("not a hex string") + .try_into() + .unwrap(); + + let domain_separator = get_domain_separator(*CHAIN_ID, *PERMIT2); + + assert_eq!(domain_separator, expected); + } + + #[test] + fn token_permissions_hash() { + let permitted = TokenPermissions { + token: *TOKEN, + amount: *AMOUNT, + }; + + let token_permissions_hash = hash_token_permissions(&permitted); + + let expected: [u8; 32] = + hex::decode("5242218a35f9737910ead9257a854c115121a89692e54d1f2f754db12825cef8") + .expect("not a hex string") + .try_into() + .unwrap(); + + assert_eq!(token_permissions_hash, expected); + } + + #[test] + fn permit_transfer_from_hash() { + let permit = PermitTransferFrom { + permitted: TokenPermissions { + token: *TOKEN, + amount: *AMOUNT, + }, + spender: *SPENDER, + nonce: *NONCE, + deadline: *DEADLINE, + }; + + let token_permissions_hash = hash_token_permissions(&permit.permitted); + + let permit_transfer_from_hash = hash_permit_transfer_from(&permit, &token_permissions_hash); + + let expected: [u8; 32] = + hex::decode("fbe5abfd6a552891eead18d711453fc83e86303fb368c7c56e7255752b73aa1b") + .expect("not a hex string") + .try_into() + .unwrap(); + + assert_eq!(permit_transfer_from_hash, expected); + } + + #[test] + fn eip712_hash() { + let domain_separator = get_domain_separator(*CHAIN_ID, *PERMIT2); + + let permit = PermitTransferFrom { + permitted: TokenPermissions { + token: *TOKEN, + amount: *AMOUNT, + }, + spender: *SPENDER, + nonce: *NONCE, + deadline: *DEADLINE, + }; + + let hash = get_eip712_hash(&permit, &domain_separator); + + let expected: [u8; 32] = + hex::decode("243c51e5752350b2c69b878a05d996cb42f1b60f6c9bb74d2c057af3c1e40883") + .expect("not a hex string") + .try_into() + .expect("not a 32 byte array"); + + assert_eq!(hash, expected); + } + + #[test] + #[cfg(not(feature = "eip_155"))] + fn permit_signature() { + use super::{destringify_private_key, sign_message}; + + let message: [u8; 32] = + hex::decode("243c51e5752350b2c69b878a05d996cb42f1b60f6c9bb74d2c057af3c1e40883") + .expect("not a hex string") + .try_into() + .expect("not a 32 byte array"); + + let (r, s, v) = sign_message( + &message, + &destringify_private_key( + "0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d", + ), + ); + + let expected: [u8; 32] = + hex::decode("be3b4cce436d02fa6e5588010762887c6268b054f68f880d2ecf6675b4819d93") + .expect("not a hex string") + .try_into() + .unwrap(); + + assert_eq!(r, expected); + + let expected: [u8; 32] = + hex::decode("5e5c927d0752572e07d43c58a1c184da6d6613a46a14222a3d2009c8819283bc") + .expect("not a hex string") + .try_into() + .unwrap(); + + assert_eq!(s, expected); + + let expected = 28u8; + + assert_eq!(v, expected); + } +} diff --git a/crates/shielder-rust-sdk/src/powers_of_tau.rs b/crates/shielder-rust-sdk/src/powers_of_tau.rs new file mode 100644 index 00000000..02c5160c --- /dev/null +++ b/crates/shielder-rust-sdk/src/powers_of_tau.rs @@ -0,0 +1,272 @@ +use std::{ + fs::File, + io, + io::{Read, Seek, SeekFrom}, + path::PathBuf, +}; + +use byteorder::{LittleEndian, ReadBytesExt}; +use halo2_proofs::{ + arithmetic::{parallelize, CurveAffine}, + poly::commitment::ParamsProver, + SerdeFormat, +}; +use halo2curves::{ + bn256::Bn256, + group::ff::{Field, PrimeField}, + pairing::Engine, +}; +use num_bigint::BigUint; +use shielder_circuits::{circuits::Params as Srs, G1Affine}; + +pub const HEADER_SIZE_OFFSET: u64 = 16; +pub const HEADER_OFFSET: u64 = HEADER_SIZE_OFFSET + 8; + +/// Specifies the format of the ptau input file +#[derive(Debug, Clone, Copy)] +pub enum Format { + /// halo2 format that can be readily imported + Raw, + /// Perpetual powers of tau fromat (see https://github.com/privacy-scaling-explorations/perpetualpowersoftau) + /// This the same format as snarkjs (https://github.com/iden3/snarkjs/blob/master/src/powersoftau_import.js) + /// produces + PerpetualPowersOfTau, +} + +pub fn get_ptau_file_path(k: u32, format: Format) -> PathBuf { + let file = match format { + Format::Raw => &format!("ppot_0080_{}_raw", k), + Format::PerpetualPowersOfTau => &format!("ppot_0080_{}.ptau", k), + }; + [env!("CARGO_MANIFEST_DIR"), "../../resources", file] + .iter() + .collect() +} + +/// Entry point +/// Will read a ptau file in one of the `Format` representations +/// +/// SnarkJS .ptau file schema: https://github.com/iden3/snarkjs/blob/9e6cfc230e733242d55913ce85b62efb6a9cb0a8/src/powersoftau_new.js#L21 +/// See also: https://github.com/dcbuild3r/ptau-deserializer/blob/6f6fe6f7c8a2773fc04835b445ab67a806b6bba2/deserialize/ptau.go#L256 +pub fn read(ptau_file: PathBuf, format: Format) -> io::Result { + let mut reader = File::open(ptau_file)?; + match format { + Format::Raw => Srs::read_custom(&mut reader, SerdeFormat::RawBytes), + Format::PerpetualPowersOfTau => { + let k = read_k(&mut reader)?; + let n = 1 << k; + let g: Vec = read_g1::(&mut reader, n)?; + let [g2, s_g2]: [_; 2] = read_g2::(&mut reader, 2)?.try_into().unwrap(); + + Ok(Srs::new(k).from_parts(k, g, None, g2, s_g2)) + } + } +} + +fn read_header_size(reader: &mut R) -> u64 { + reader.seek(SeekFrom::Start(HEADER_SIZE_OFFSET)).unwrap(); + reader.read_u64::().unwrap() +} + +fn read_k(reader: &mut File) -> io::Result { + let k_offset = HEADER_OFFSET + read_header_size(reader) - 8; + reader.seek(SeekFrom::Start(k_offset))?; + reader.read_u32::() +} + +fn field_repr_size() -> usize { + F::Repr::default().as_ref().len() +} + +/// Computes the Montgomery constant R for a given prime field F +fn montgomery_r() -> F { + // Create a placeholder R value + let mut binary_representation = F::Repr::default(); + + // Compute the modulus of the field + 1 + let modulus = BigUint::from_bytes_le((-F::ONE).to_repr().as_ref()) + 1u64; + + // Compute the Montgomery R value: 2^(bit_size of F) % modulus + let r_value = (BigUint::from(1u64) << (8 * binary_representation.as_ref().len())) % modulus; + + // Copy the calculated Montgomery R value into the binary representation + binary_representation + .as_mut() + .copy_from_slice(&r_value.to_bytes_le()); + + // return R as a field element type + F::from_repr(binary_representation).unwrap() +} + +fn g2_offset(reader: &mut File) -> io::Result +where + E: Engine, + E::G1Affine: CurveAffine, + E::G2Affine: CurveAffine, +{ + let base_size = field_repr_size::<::Base>(); + Ok(g1_offset(reader) + (2 * base_size * (2 * (1 << read_k(reader)?) - 1)) as u64 + 12) +} + +fn g1_offset(reader: &mut File) -> u64 { + HEADER_OFFSET + read_header_size(reader) + 12 +} + +fn read_g2(reader: &mut File, n: usize) -> io::Result> +where + E: Engine, + E::G1Affine: CurveAffine, + E::G2Affine: CurveAffine, +{ + // seek starting place + let offset = g2_offset::(reader)?; + reader.seek(SeekFrom::Start(offset))?; + + let mut binary_representations = + vec![[<::Base as PrimeField>::Repr::default(); 2]; n]; + + for binary_representation in binary_representations.iter_mut() { + reader.read_exact(binary_representation[0].as_mut())?; + reader.read_exact(binary_representation[1].as_mut())?; + } + + let montgomery_r_inverse = montgomery_r::<::Base>() + .invert() + .unwrap(); + + let mut points = vec![E::G2Affine::default(); n]; + + let g1_base_size = field_repr_size::<::Base>(); + + parallelize(&mut points, |points, start| { + for (i, point) in points.iter_mut().enumerate() { + let representations = + binary_representations[start + i].map(|mut binary_representation| { + let mut g1_base_representations = + [<::Base as PrimeField>::Repr::default(); 2]; + + g1_base_representations[0] + .as_mut() + .copy_from_slice(&binary_representation.as_ref()[..g1_base_size]); + + g1_base_representations[1] + .as_mut() + .copy_from_slice(&binary_representation.as_ref()[g1_base_size..]); + + let g1_bases = g1_base_representations.map(|g1_base_representation| { + ::Base::from_repr(g1_base_representation) + .unwrap() + * montgomery_r_inverse + }); + + binary_representation.as_mut()[..g1_base_size] + .copy_from_slice(g1_bases[0].to_repr().as_ref()); + binary_representation.as_mut()[g1_base_size..] + .copy_from_slice(g1_bases[1].to_repr().as_ref()); + + binary_representation + }); + + let [x, y] = representations + .map(|repr| ::Base::from_repr(repr).unwrap()); + + *point = E::G2Affine::from_xy(x, y).unwrap(); + } + }); + + Ok(points) +} + +pub fn read_g1(reader: &mut File, n: usize) -> io::Result> +where + E: Engine, + E::G1Affine: CurveAffine, +{ + // seek starting place + let offset = g1_offset(reader); + reader.seek(SeekFrom::Start(offset)).unwrap(); + + let mut binary_representations = + vec![<::Base as PrimeField>::Repr::default(); 2 * n]; + + for binary_representation in binary_representations.iter_mut() { + reader.read_exact(binary_representation.as_mut())?; + } + + let montgomery_r_inverse = montgomery_r::<::Base>() + .invert() + .unwrap(); + + let mut points = vec![E::G1Affine::default(); n]; + + parallelize(&mut points, |points, start| { + for (i, point) in points.iter_mut().enumerate() { + let x = ::Base::from_repr( + binary_representations[2 * (start + i)], + ) + .unwrap() + * montgomery_r_inverse; + + let y = ::Base::from_repr( + binary_representations[2 * (start + i) + 1], + ) + .unwrap() + * montgomery_r_inverse; + + *point = E::G1Affine::from_xy(x, y).unwrap(); + } + }); + + Ok(points) +} + +#[cfg(test)] +mod tests { + + use halo2_proofs::poly::{ + commitment::{Blind, Params as _, ParamsProver}, + EvaluationDomain, + }; + use halo2curves::bn256::Fr; + use rand::rngs::OsRng; + use shielder_circuits::Field; + + use super::read; + use crate::powers_of_tau::{get_ptau_file_path, Format}; + + #[test] + fn test_commit_lagrange() { + let srs = read( + get_ptau_file_path(11, Format::PerpetualPowersOfTau), + Format::PerpetualPowersOfTau, + ) + .unwrap(); + + let domain = EvaluationDomain::new(1, srs.k()); + let mut a = domain.empty_lagrange(); + for (i, a) in a.iter_mut().enumerate() { + *a = Fr::from(i as u64); + } + let b = domain.lagrange_to_coeff(a.clone()); + let alpha = Blind(Fr::random(OsRng)); + + assert_eq!(srs.commit(&b, alpha), srs.commit_lagrange(&a, alpha)); + } + + #[test] + fn raw_equals_perpetual() { + let raw_ptau = read(get_ptau_file_path(11, Format::Raw), Format::Raw).unwrap(); + + let perpetual_ptau = read( + get_ptau_file_path(11, Format::PerpetualPowersOfTau), + Format::PerpetualPowersOfTau, + ) + .unwrap(); + + assert_eq!(raw_ptau.n(), perpetual_ptau.n()); + assert_eq!(raw_ptau.k(), perpetual_ptau.k()); + assert_eq!(raw_ptau.g2(), perpetual_ptau.g2()); + assert_eq!(raw_ptau.s_g2(), perpetual_ptau.s_g2()); + assert_eq!(raw_ptau.get_g(), perpetual_ptau.get_g()); + } +} diff --git a/crates/shielder-wasm/.cargo/config.toml b/crates/shielder-wasm/.cargo/config.toml new file mode 100644 index 00000000..0903ff7a --- /dev/null +++ b/crates/shielder-wasm/.cargo/config.toml @@ -0,0 +1,47 @@ +[target.wasm32-unknown-unknown] +rustflags = [ + "-C", + "target-feature=+atomics,+bulk-memory,+mutable-globals", + "-C", + "link-arg=--max-memory=4294967296", +] + +[profile.dev] +opt-level = 3 +debug = 2 # change to 0 or 2 for more or less debug info +overflow-checks = true +incremental = true + +# Local "release" mode, more optimized than dev but faster to compile than release +[profile.local] +inherits = "dev" +opt-level = 3 +# Set this to 1 or 2 to get more useful backtraces +debug = 1 +debug-assertions = false +panic = 'unwind' +# better recompile times +incremental = true +lto = "thin" +codegen-units = 16 + +[profile.release] +opt-level = 3 +debug = false +debug-assertions = false +lto = "fat" +# `codegen-units = 1` can lead to WORSE performance - always bench to find best profile for your machine! +# codegen-units = 1 +panic = "unwind" +incremental = false + +[profile.bench] +opt-level = 3 +debug = true +lto = true +codegen-units = 1 + +[profile.test] +opt-level = 3 +debug = true +lto = true diff --git a/crates/shielder-wasm/.gitignore b/crates/shielder-wasm/.gitignore new file mode 100644 index 00000000..d198e4b8 --- /dev/null +++ b/crates/shielder-wasm/.gitignore @@ -0,0 +1,2 @@ +pkg/ +artifacts/ \ No newline at end of file diff --git a/crates/shielder-wasm/Cargo.toml b/crates/shielder-wasm/Cargo.toml new file mode 100644 index 00000000..e513d231 --- /dev/null +++ b/crates/shielder-wasm/Cargo.toml @@ -0,0 +1,47 @@ +[package] +name = "shielder-wasm" +version = "0.1.0" +description = "WASM bindings to shielder circuits for browser" + +edition.workspace = true +authors = ["Cardinal", "Piotr Roslaniec "] +homepage.workspace = true +license = "GPL-3.0-only AND Apache-2.0" +categories.workspace = true +repository.workspace = true + +[lib] +crate-type = ["cdylib", "rlib"] + +[dependencies] +console_error_panic_hook = { workspace = true } +getrandom = { workspace = true, features = ["js"] } +halo2_poseidon = { workspace = true } +halo2_proofs = { workspace = true } +rand = { workspace = true, features = ["small_rng"] } +rand_chacha = { workspace = true } +rand_core = { workspace = true } +rayon = { workspace = true, optional = true } +sha2 = { workspace = true } +shielder-circuits = { workspace = true } +shielder-rust-sdk = { workspace = true, features = ["account", "conversion", "parameter_generation"] } +wasm-bindgen-rayon = { workspace = true, optional = true } +wasm-bindgen.workspace = true + +[build-dependencies] +rand = { workspace = true, features = ["small_rng"] } +shielder-circuits = { workspace = true } +shielder-rust-sdk = { workspace = true, features = ["parameter_generation", "powers_of_tau"] } + +[features] +default = ["std", "merkle"] +merkle = [] +std = [] +multithreading = [ + "rayon", + "wasm-bindgen-rayon", + "shielder-circuits/multithreading", +] + +[package.metadata.wasm-pack.profile.release] +wasm-opt = ['-O4', '-g'] diff --git a/crates/shielder-wasm/Makefile b/crates/shielder-wasm/Makefile new file mode 100644 index 00000000..311fa57d --- /dev/null +++ b/crates/shielder-wasm/Makefile @@ -0,0 +1,38 @@ +# `sed -i` is used differently under MacOS +OS := $(shell uname) +ifeq ($(OS), Darwin) + SED_CMD := sed -i '' +else + SED_CMD := sed -i +endif + +.PHONY: all +all: clean build-pkg update-package-web remove-unused-files + +.PHONY: clean +clean: + rm -rf pkg* + +.PHONY: build-pkg +build-pkg: + wasm-pack build --release --target web --out-dir pkg/pkg-web-singlethreaded -- \ + --target="wasm32-unknown-unknown" \ + -Z build-std="panic_abort,std" + wasm-pack build --release --target web --out-dir pkg/pkg-web-multithreaded -- \ + --features multithreading \ + --target="wasm32-unknown-unknown" \ + -Z build-std="panic_abort,std" + cp package.template.json pkg/package.json + +.PHONY: update-package-web +update-package-web: + $(SED_CMD) "s|import initWbg, { wbg_rayon_start_worker } from '../../../';|import initWbg, { wbg_rayon_start_worker } from '../../../shielder_wasm';|g" pkg/pkg-web-multithreaded/snippets/wasm-bindgen-rayon-3e04391371ad0a8e/src/workerHelpers.worker.js + +.PHONY: remove-unused-files +remove-unused-files: + (cd pkg/pkg-web-singlethreaded && rm README.md package.json .gitignore) + (cd pkg/pkg-web-multithreaded && rm README.md package.json .gitignore) + +.PHONY: test +test: + cargo test --release diff --git a/crates/shielder-wasm/README.md b/crates/shielder-wasm/README.md new file mode 100644 index 00000000..534ff5cd --- /dev/null +++ b/crates/shielder-wasm/README.md @@ -0,0 +1,13 @@ +# `shielder-wasm` + +This crates provides WASM bindings for the circuits from `shielder-circuits` crate and for some parts of `shielder-rust-sdk`. + +We use the `wasm-pack` tool to generate the bindings. You can find the generated bindings in the `pkg` directory. + +To build the project, run: + +```bash +make +``` + +Inspect the `Makefile` and the resulting `pkg` directory for more information. diff --git a/crates/shielder-wasm/build.rs b/crates/shielder-wasm/build.rs new file mode 100644 index 00000000..c44333e8 --- /dev/null +++ b/crates/shielder-wasm/build.rs @@ -0,0 +1,89 @@ +use rand::RngCore; +/// This script builds artifacts, which are later +/// embedded into the wasm binary. +/// To speedup the build process, we cache the artifacts after the first build. +/// +/// When working locally, the `artifacts/` directory should be cleaned after the circuits are changed. +use shielder_circuits::circuits::merkle::MerkleCircuit; +use shielder_circuits::{circuits::Params, merkle::MerkleProverKnowledge, ProverKnowledge}; +/// This script builds artifacts, which are later +/// embedded into the wasm binary. +/// To speedup the build process, we cache the artifacts after the first build. +/// +/// When working locally, the `artifacts/` directory should be cleaned after the circuits are changed. +use shielder_circuits::{ + consts::{merkle_constants::NOTE_TREE_HEIGHT, RANGE_PROOF_CHUNK_SIZE}, + deposit::DepositCircuit, + generate_keys_with_min_k, + marshall::{marshall_params, marshall_path, marshall_pk}, + new_account::NewAccountCircuit, + withdraw::WithdrawCircuit, + Circuit, F, MAX_K, +}; +use shielder_rust_sdk::{ + parameter_generation, + powers_of_tau::{get_ptau_file_path, read as read_setup_parameters, Format}, +}; + +/// This function is used to generate the artifacts for the circuit, i.e. hardcoded keys +/// and parameters. Saves results to `params.bin` and `pk.bin`. +fn gen_params_pk(circuit_name: &str, full_params: &Params) +where + C: Circuit + Default, +{ + std::fs::create_dir_all(format!("artifacts/{}", circuit_name)) + .expect("Failed to create directory"); + let (params, k, pk, _) = generate_keys_with_min_k::(full_params.clone()) + .expect("keys should not fail to generate"); + let params_bytes = marshall_params(¶ms).expect("Failed to marshall params"); + std::fs::write( + format!("artifacts/{}/params.bin", circuit_name), + params_bytes, + ) + .expect("Failed to write params.bin"); + let key_bytes = marshall_pk(k, &pk).expect("Failed to marshall pk"); + std::fs::write(format!("artifacts/{}/pk.bin", circuit_name), key_bytes) + .expect("Failed to write pk.bin"); +} + +/// This function is used to generate the artifacts for the DepositCircuit +fn gen_deposit(full_params: &Params) { + gen_params_pk::>("deposit", full_params); +} + +/// This function is used to generate the artifacts for the NewAccountCircuit +fn generate_new_account(full_params: &Params) { + gen_params_pk::>("new_account", full_params); +} + +/// This function is used to generate the artifacts for the WithdrawCircuit +fn generate_withdraw(full_params: &Params) { + gen_params_pk::>("withdraw", full_params); +} + +/// This function is used to generate the artifacts for the MerkleCircuit +/// and the path to the root, leaf and path. +fn gen_merkle(full_params: &Params, rng: &mut impl RngCore) { + gen_params_pk::>("merkle", full_params); + + let merkle_knowledge = + MerkleProverKnowledge::::random_correct_example(rng); + let path_bytes = marshall_path(&merkle_knowledge.leaf, &merkle_knowledge.path); + std::fs::write("artifacts/merkle/path.bin", path_bytes).expect("Failed to write path.bin"); +} + +fn main() { + let mut rng = parameter_generation::rng(); + + let full_params = read_setup_parameters( + get_ptau_file_path(MAX_K, Format::PerpetualPowersOfTau), + Format::PerpetualPowersOfTau, + ) + .expect("failed to read parameters from the ptau file"); + + gen_deposit(&full_params); + generate_new_account(&full_params); + generate_withdraw(&full_params); + gen_merkle(&full_params, &mut rng); + println!("cargo:rerun-if-changed=../shielder-circuits"); +} diff --git a/crates/shielder-wasm/package.template.json b/crates/shielder-wasm/package.template.json new file mode 100644 index 00000000..28c6e755 --- /dev/null +++ b/crates/shielder-wasm/package.template.json @@ -0,0 +1,19 @@ +{ + "name": "shielder-wasm", + "version": "0.0.1", + "description": "WASM bindings for Shielder cryptography. Intended for use in web applications.", + "license": "Apache-2.0", + "author": "Cardinal", + "contributors": [ + { + "name": "Piotr Roslaniec", + "email": "p.roslaniec@gmail.com" + } + ], + "exports": { + "./web-singlethreaded": "./pkg-web-singlethreaded/shielder_wasm.js", + "./web-multithreaded": "./pkg-web-multithreaded/shielder_wasm.js" + }, + "files": ["pkg-web-singlethreaded/**/*.*", "pkg-web-multithreaded/**/*.*"], + "sideEffects": ["pkg-web-multithreaded/snippets/**/*.*"] +} diff --git a/crates/shielder-wasm/src/circuits/deposit.rs b/crates/shielder-wasm/src/circuits/deposit.rs new file mode 100644 index 00000000..521b2e74 --- /dev/null +++ b/crates/shielder-wasm/src/circuits/deposit.rs @@ -0,0 +1,81 @@ +use alloc::vec::Vec; + +use shielder_circuits::deposit::{DepositInstance, DepositProverKnowledge}; +use wasm_bindgen::{prelude::wasm_bindgen, JsError}; + +use crate::{vec_to_f, vec_to_path}; + +#[wasm_bindgen] +extern "C" { + #[wasm_bindgen(js_namespace = console)] + fn log(s: &str); +} + +#[wasm_bindgen] +#[derive(Clone, Debug)] +pub struct DepositCircuit(super::DepositCircuit); + +#[wasm_bindgen] +impl DepositCircuit { + #[wasm_bindgen(constructor)] + pub fn new_pronto() -> Self { + log("Creating DepositCircuit (pronto)"); + DepositCircuit(super::DepositCircuit::new_pronto()) + } + + #[allow(clippy::too_many_arguments)] + pub fn prove( + &mut self, + id: Vec, + nonce: Vec, + nullifier_old: Vec, + trapdoor_old: Vec, + account_balance_old: Vec, + path: Vec, + value: Vec, + nullifier_new: Vec, + trapdoor_new: Vec, + ) -> Vec { + log("Proving DepositCircuit"); + self.0.prove( + &DepositProverKnowledge { + id: vec_to_f(id), + nonce: vec_to_f(nonce), + nullifier_old: vec_to_f(nullifier_old), + trapdoor_old: vec_to_f(trapdoor_old), + account_old_balance: vec_to_f(account_balance_old), + path: vec_to_path(path), + deposit_value: vec_to_f(value), + nullifier_new: vec_to_f(nullifier_new), + trapdoor_new: vec_to_f(trapdoor_new), + }, + &mut rand::thread_rng(), + ) + } + + #[wasm_bindgen] + pub fn verify( + &mut self, + id_hiding: Vec, + merkle_root: Vec, + h_nullifier_old: Vec, + h_note_new: Vec, + value: Vec, + proof: Vec, + ) -> Result<(), JsError> { + log("Verifying DepositCircuit"); + + let public_input = |input: DepositInstance| { + let value = match input { + DepositInstance::IdHiding => &id_hiding, + DepositInstance::MerkleRoot => &merkle_root, + DepositInstance::HashedOldNullifier => &h_nullifier_old, + DepositInstance::HashedNewNote => &h_note_new, + DepositInstance::DepositValue => &value, + }; + vec_to_f(value.clone()) + }; + + self.0.verify(&public_input, proof).map_err(JsError::from) + } +} diff --git a/crates/shielder-wasm/src/circuits/merkle/mod.rs b/crates/shielder-wasm/src/circuits/merkle/mod.rs new file mode 100644 index 00000000..931fc417 --- /dev/null +++ b/crates/shielder-wasm/src/circuits/merkle/mod.rs @@ -0,0 +1,180 @@ +use alloc::{format, string::String, vec, vec::Vec}; + +use rand_core::{RngCore, SeedableRng}; +use sha2::Digest; +use shielder_circuits::{ + circuits::{merkle::MerkleCircuit as MerkleCircuitOrig, Params, ProvingKey, VerifyingKey}, + consts::merkle_constants::NOTE_TREE_HEIGHT, + generate_keys_with_min_k, generate_proof, generate_setup_params, + marshall::{unmarshall_params, unmarshall_path, unmarshall_pk}, + merkle::MerkleProverKnowledge, + verify, CircuitCost, Field, ProverKnowledge, PublicInputProvider, F, G1, MAX_K, SERDE_FORMAT, +}; + +pub mod wasm; + +#[derive(Clone, Debug)] +pub struct MerkleCircuit { + params: Params, + pk: ProvingKey, + vk: VerifyingKey, + k: u32, + proof: Vec, + values: MerkleProverKnowledge, + tree_height: usize, +} + +impl MerkleCircuit { + pub fn new(rng: &mut impl RngCore) -> Self { + let values = MerkleProverKnowledge::::random_correct_example(rng); + + let (params, k, pk, vk) = + generate_keys_with_min_k::>( + generate_setup_params(MAX_K, rng), + ) + .expect("keys should not fail to generate"); + + MerkleCircuit { + params, + pk, + vk, + k, + proof: vec![], + values, + tree_height: NOTE_TREE_HEIGHT, + } + } + + /// Create a new MerkleCircuit with hardcoded keys and path, which is faster than generating new keys. + /// If `seed` is provided, it will be used for the penultimate layer of the Merkle path + /// (this is for making the proof dependent on the seed). + /// + /// Complexity: + /// - decoding parameters and keys from raw bytes + /// - decoding path from raw bytes + /// - optionally, two Poseidon hashes (iff `seed` is provided) + pub fn new_pronto(seed: Option) -> Self { + let params = unmarshall_params(include_bytes!("../../../artifacts/merkle/params.bin")) + .expect("Failed to unmarshall params"); + let (k, pk) = unmarshall_pk::>(include_bytes!( + "../../../artifacts/merkle/pk.bin" + )) + .expect("Failed to unmarshall pk"); + + let vk = pk.get_vk().clone(); + let (leaf, mut path) = + unmarshall_path::(include_bytes!("../../../artifacts/merkle/path.bin")); + + if let Some(seed) = seed { + let bytes = sha2::Sha256::digest(seed.as_bytes()); + let seeded_node = F::random(rand_chacha::ChaCha12Rng::from_seed(bytes.into())); + + path[NOTE_TREE_HEIGHT - 1][1] = seeded_node; + } + + let values = MerkleProverKnowledge { leaf, path }; + + MerkleCircuit { + params, + pk, + vk, + k, + proof: vec![], + values, + tree_height: NOTE_TREE_HEIGHT, + } + } + + pub fn k(&self) -> u32 { + self.k + } + + pub fn vk(&self) -> VerifyingKey { + self.vk.clone() + } + + pub fn pk(&self) -> ProvingKey { + self.pk.clone() + } + + pub fn params(&self) -> Params { + self.params.clone() + } + + pub fn proof(&self) -> Option> { + if self.proof.is_empty() { + return None; + } + Some(self.proof.clone()) + } + + pub fn tree_height(&self) -> u32 { + self.tree_height as u32 + } + + pub fn circuit_cost( + &self, + rng: &mut impl RngCore, + ) -> CircuitCost> { + let merkle_prover_knowledge = + MerkleProverKnowledge::::random_correct_example(rng); + let circuit = merkle_prover_knowledge.create_circuit(); + CircuitCost::::measure(self.k, &circuit) + } + + pub fn verifying_key_size_bytes(&self) -> usize { + // Using `to_bytes` because `VerifyingKey::bytes_length` is private. + self.vk.to_bytes(SERDE_FORMAT).len() + } + + //TODO: Change to return a Result(String, Error). This is mostly fixing wasm-frontend interaction. + pub fn prove(&mut self, rng: &mut impl RngCore) -> String { + let circuit = self.values.create_circuit(); + self.proof = generate_proof( + &self.params, + &self.pk, + circuit, + &self.values.serialize_public_input(), + rng, + ); + format!("{:?}", self.proof) + } + + //TODO: Change to return a Result(String, Error). This is mostly fixing wasm-frontend interaction. + pub fn verify(&self) -> String { + if self.proof.is_empty() { + panic!("Proof was not initialized."); + } + + format!( + "{:?}", + verify( + &self.params, + &self.vk, + &self.proof, + &self.values.serialize_public_input(), + ) + ) + } +} + +#[cfg(test)] +mod tests { + use alloc::string::String; + + use super::MerkleCircuit; + + #[test] + fn pronto() { + let mut circuit = MerkleCircuit::new_pronto(None); + circuit.prove(&mut rand::thread_rng()); + circuit.verify(); + } + + #[test] + fn pronto_with_seed() { + let mut circuit = MerkleCircuit::new_pronto(Some(String::from("0xethereum address"))); + circuit.prove(&mut rand::thread_rng()); + circuit.verify(); + } +} diff --git a/crates/shielder-wasm/src/circuits/merkle/wasm.rs b/crates/shielder-wasm/src/circuits/merkle/wasm.rs new file mode 100644 index 00000000..027c56a5 --- /dev/null +++ b/crates/shielder-wasm/src/circuits/merkle/wasm.rs @@ -0,0 +1,149 @@ +use alloc::{format, string::String, vec::Vec}; + +use console_error_panic_hook; +use shielder_circuits::consts::merkle_constants::{ARITY, NOTE_TREE_HEIGHT}; +use wasm_bindgen::prelude::wasm_bindgen; + +#[wasm_bindgen] +extern "C" { + #[wasm_bindgen(js_namespace = console)] + fn log(s: &str); +} + +#[wasm_bindgen] +pub fn set_panic_hook() { + console_error_panic_hook::set_once(); +} + +#[wasm_bindgen] +#[derive(Clone, Debug)] +pub struct Config { + #[wasm_bindgen] + pub k: u32, + + #[wasm_bindgen(js_name = "treeArity")] + pub tree_arity: u32, + + #[wasm_bindgen(js_name = "treeHeight")] + pub tree_height: u32, + + #[wasm_bindgen(js_name = "log2Leaves")] + pub log2_leaves: u32, +} + +#[wasm_bindgen] +#[derive(Clone, Debug)] +pub struct CircuitCost { + proof_size: String, + proof_size_bytes: usize, + + marginal_proof_size: String, + marginal_proof_size_bytes: usize, + + verifying_key_size_bytes: usize, + + circuit_cost_str: String, +} + +#[wasm_bindgen] +impl CircuitCost { + #[wasm_bindgen(getter, js_name = "proofSize")] + pub fn proof_size(&self) -> String { + self.proof_size.clone() + } + + #[wasm_bindgen(getter, js_name = "proofSizeBytes")] + pub fn proof_size_bytes(&self) -> usize { + self.proof_size_bytes + } + + #[wasm_bindgen(getter, js_name = "marginalProofSize")] + pub fn marginal_proof_size(&self) -> String { + self.marginal_proof_size.clone() + } + + #[wasm_bindgen(getter, js_name = "marginalProofSizeBytes")] + pub fn marginal_proof_size_bytes(&self) -> usize { + self.marginal_proof_size_bytes + } + + #[wasm_bindgen(getter, js_name = "verifyingKeySizeBytes")] + pub fn verifying_key_size_bytes(&self) -> usize { + self.verifying_key_size_bytes + } + + #[wasm_bindgen(getter, js_name = "circuitCostStr")] + pub fn circuit_cost_str(&self) -> String { + self.circuit_cost_str.clone() + } +} + +#[wasm_bindgen] +#[derive(Clone, Debug)] +pub struct MerkleCircuit(super::MerkleCircuit); + +#[wasm_bindgen] +impl MerkleCircuit { + #[wasm_bindgen(constructor)] + pub fn new_pronto(seed: Option) -> Self { + log("Creating MerkleCircuit (pronto)"); + MerkleCircuit(super::MerkleCircuit::new_pronto(seed)) + } + + #[wasm_bindgen] + pub fn prove(&mut self) -> String { + log("Proving MerkleCircuit"); + self.0.prove(&mut rand::thread_rng()) + } + + #[wasm_bindgen(getter)] + pub fn config(&self) -> Config { + // Using a larger type to avoid overflow + let arity = ARITY as f64; + let tree_height = NOTE_TREE_HEIGHT as f64; + let log2_leaves = f64::powf(arity, tree_height).log2() as u32; + Config { + k: self.0.k(), + tree_height: self.0.tree_height(), + tree_arity: ARITY as u32, + log2_leaves, + } + } + + #[wasm_bindgen(getter, js_name = "circuitCost")] + pub fn circuit_cost(&self) -> CircuitCost { + let cost = self.0.circuit_cost(&mut rand::thread_rng()); + let proof_size_struct = cost.proof_size(1); + let marginal_proof_size_struct = cost.marginal_proof_size(); + + // TODO: Use serde_json to serialize the struct instead; requires adding Serialize trait to CircuitCost + let proof_size = format!("{:?}", proof_size_struct); + let marginal_proof_size = format!("{:?}", marginal_proof_size_struct); + + let proof_size_bytes = usize::from(proof_size_struct); + let marginal_proof_size_bytes = usize::from(marginal_proof_size_struct); + + let verifying_key_size_bytes = self.0.verifying_key_size_bytes(); + + CircuitCost { + proof_size, + proof_size_bytes, + marginal_proof_size, + marginal_proof_size_bytes, + verifying_key_size_bytes, + circuit_cost_str: format!("{:?}", cost), + } + } + + #[wasm_bindgen] + pub fn verify(&mut self) -> String { + log("Verifying MerkleCircuit"); + self.0.verify() + } + + #[wasm_bindgen] + pub fn proof(&mut self) -> Vec { + log("Verifying MerkleCircuit"); + self.0.proof.clone() + } +} diff --git a/crates/shielder-wasm/src/circuits/mod.rs b/crates/shielder-wasm/src/circuits/mod.rs new file mode 100644 index 00000000..5dba3f2d --- /dev/null +++ b/crates/shielder-wasm/src/circuits/mod.rs @@ -0,0 +1,194 @@ +use alloc::vec::Vec; +use core::marker::PhantomData; + +use halo2_proofs::plonk::Error; +use rand::RngCore; +use shielder_circuits::{ + circuits::{Params, ProvingKey, VerifyingKey}, + consts::RANGE_PROOF_CHUNK_SIZE, + deposit::DepositProverKnowledge, + generate_keys_with_min_k, generate_proof, generate_setup_params, + marshall::{unmarshall_params, unmarshall_pk}, + new_account::NewAccountProverKnowledge, + verify, + withdraw::WithdrawProverKnowledge, + ProverKnowledge, PublicInputProvider, F, MAX_K, +}; + +#[cfg(feature = "merkle")] +pub mod merkle; + +pub mod deposit; +pub mod new_account; +pub mod withdraw; + +pub trait WasmCircuit { + fn load_files() -> (Params, ProvingKey, u32); +} + +#[derive(Clone, Debug)] +pub struct Circuit> { + params: Params, + pk: ProvingKey, + vk: VerifyingKey, + k: u32, + _phantom: PhantomData, +} + +impl WasmCircuit for Circuit> { + fn load_files() -> (Params, ProvingKey, u32) { + let params = unmarshall_params(include_bytes!("../../artifacts/deposit/params.bin")) + .expect("Failed to unmarshall params"); + + let (k, pk) = unmarshall_pk::< + as ProverKnowledge>::Circuit, + >(include_bytes!("../../artifacts/deposit/pk.bin")) + .expect("Failed to unmarshall pk"); + + (params, pk, k) + } +} + +impl WasmCircuit for Circuit> { + fn load_files() -> (Params, ProvingKey, u32) { + let params = unmarshall_params(include_bytes!("../../artifacts/new_account/params.bin")) + .expect("Failed to unmarshall params"); + let (k, pk) = + unmarshall_pk::< as ProverKnowledge>::Circuit>( + include_bytes!("../../artifacts/new_account/pk.bin"), + ) + .expect("Failed to unmarshall pk"); + + (params, pk, k) + } +} + +impl WasmCircuit for Circuit> { + fn load_files() -> (Params, ProvingKey, u32) { + let params = unmarshall_params(include_bytes!("../../artifacts/withdraw/params.bin")) + .expect("Failed to unmarshall params"); + let (k, pk) = unmarshall_pk::< + as ProverKnowledge>::Circuit, + >(include_bytes!("../../artifacts/withdraw/pk.bin")) + .expect("Failed to unmarshall pk"); + + (params, pk, k) + } +} + +impl> Circuit +where + Circuit: WasmCircuit, +{ + pub fn k(&self) -> u32 { + self.k + } + + pub fn vk(&self) -> VerifyingKey { + self.vk.clone() + } + + pub fn pk(&self) -> ProvingKey { + self.pk.clone() + } + + pub fn params(&self) -> Params { + self.params.clone() + } + + pub fn new(rng: &mut impl RngCore) -> Self { + let (params, k, pk, vk) = + generate_keys_with_min_k::(generate_setup_params(MAX_K, rng)) + .expect("keys should not fail to generate"); + + Circuit { + params, + pk, + vk, + k, + _phantom: PhantomData, + } + } + + /// Create a new DepositCircuit with hardcoded keys, which is faster than generating new keys. + pub fn new_pronto() -> Self { + let (params, pk, k) = Self::load_files(); + + let vk = pk.get_vk().clone(); + + Circuit { + params, + pk, + vk, + k, + _phantom: PhantomData, + } + } + + pub fn prove(&mut self, values: &PK, rng: &mut impl RngCore) -> Vec { + generate_proof( + &self.params, + &self.pk, + values.create_circuit(), + &values.serialize_public_input(), + rng, + ) + } + + pub fn verify>( + &self, + pub_input_provider: &PIP, + proof: Vec, + ) -> Result<(), Error> { + verify( + &self.params, + &self.vk, + &proof, + &pub_input_provider.serialize_public_input(), + ) + } +} + +pub type DepositCircuit = Circuit>; +pub type NewAccountCircuit = Circuit>; +pub type WithdrawCircuit = Circuit>; + +#[cfg(test)] +mod tests { + use shielder_circuits::{ + consts::RANGE_PROOF_CHUNK_SIZE, deposit::DepositProverKnowledge, + new_account::NewAccountProverKnowledge, withdraw::WithdrawProverKnowledge, ProverKnowledge, + PublicInputProvider, F, + }; + + use super::{DepositCircuit, NewAccountCircuit, WithdrawCircuit}; + + #[test] + fn deposit_pronto() { + let mut rng = rand::thread_rng(); + let mut circuit = DepositCircuit::new_pronto(); + let values = + DepositProverKnowledge::::random_correct_example(&mut rng); + let proof = circuit.prove(&values, &mut rng); + circuit.verify(&values, proof).unwrap(); + } + + #[test] + fn new_account_pronto() { + let mut rng = rand::thread_rng(); + let mut circuit = NewAccountCircuit::new_pronto(); + let values = NewAccountProverKnowledge::::random_correct_example(&mut rng); + let proof = circuit.prove(&values, &mut rng); + circuit.verify(&values, proof).unwrap(); + } + + #[test] + fn withdraw_pronto() { + let mut rng = rand::thread_rng(); + let mut circuit = WithdrawCircuit::new_pronto(); + let values = + WithdrawProverKnowledge::::random_correct_example(&mut rng); + let proof = circuit.prove(&values, &mut rng); + circuit.verify(&values, proof).unwrap(); + } +} diff --git a/crates/shielder-wasm/src/circuits/new_account.rs b/crates/shielder-wasm/src/circuits/new_account.rs new file mode 100644 index 00000000..1c2f6a7d --- /dev/null +++ b/crates/shielder-wasm/src/circuits/new_account.rs @@ -0,0 +1,66 @@ +use alloc::vec::Vec; + +use shielder_circuits::new_account::{NewAccountInstance, NewAccountProverKnowledge}; +use wasm_bindgen::{prelude::wasm_bindgen, JsError}; + +use crate::vec_to_f; + +#[wasm_bindgen] +extern "C" { + #[wasm_bindgen(js_namespace = console)] + fn log(s: &str); +} + +#[wasm_bindgen] +#[derive(Clone, Debug)] +pub struct NewAccountCircuit(super::NewAccountCircuit); + +#[wasm_bindgen] +impl NewAccountCircuit { + #[wasm_bindgen(constructor)] + pub fn new_pronto() -> Self { + log("Creating NewAccountCircuit (pronto)"); + NewAccountCircuit(super::NewAccountCircuit::new_pronto()) + } + + pub fn prove( + &mut self, + id: Vec, + nullifier: Vec, + trapdoor: Vec, + initial_deposit: Vec, + ) -> Vec { + log("Proving NewAccountCircuit"); + self.0.prove( + &NewAccountProverKnowledge { + id: vec_to_f(id), + nullifier: vec_to_f(nullifier), + trapdoor: vec_to_f(trapdoor), + initial_deposit: vec_to_f(initial_deposit), + }, + &mut rand::thread_rng(), + ) + } + + #[wasm_bindgen] + pub fn verify( + &mut self, + h_note: Vec, + h_id: Vec, + initial_deposit: Vec, + proof: Vec, + ) -> Result<(), JsError> { + log("Verifying NewAccountCircuit"); + + let public_input = |input: NewAccountInstance| { + let value = match input { + NewAccountInstance::HashedId => &h_id, + NewAccountInstance::HashedNote => &h_note, + NewAccountInstance::InitialDeposit => &initial_deposit, + }; + vec_to_f(value.clone()) + }; + + self.0.verify(&public_input, proof).map_err(JsError::from) + } +} diff --git a/crates/shielder-wasm/src/circuits/withdraw.rs b/crates/shielder-wasm/src/circuits/withdraw.rs new file mode 100644 index 00000000..226faf7e --- /dev/null +++ b/crates/shielder-wasm/src/circuits/withdraw.rs @@ -0,0 +1,86 @@ +use alloc::vec::Vec; + +use shielder_circuits::withdraw::{WithdrawInstance, WithdrawProverKnowledge}; +use wasm_bindgen::{prelude::wasm_bindgen, JsError}; + +use crate::{vec_to_f, vec_to_path}; + +#[wasm_bindgen] +extern "C" { + #[wasm_bindgen(js_namespace = console)] + fn log(s: &str); +} + +#[wasm_bindgen] +#[derive(Clone, Debug)] +pub struct WithdrawCircuit(super::WithdrawCircuit); + +#[wasm_bindgen] +impl WithdrawCircuit { + #[wasm_bindgen(constructor)] + pub fn new_pronto() -> Self { + log("Creating WithdrawCircuit (pronto)"); + WithdrawCircuit(super::WithdrawCircuit::new_pronto()) + } + + #[allow(clippy::too_many_arguments)] + pub fn prove( + &mut self, + id: Vec, + nonce: Vec, + nullifier_old: Vec, + trapdoor_old: Vec, + account_balance_old: Vec, + path: Vec, + value: Vec, + nullifier_new: Vec, + trapdoor_new: Vec, + commitment: Vec, + ) -> Vec { + log("Proving WithdrawCircuit"); + self.0.prove( + &WithdrawProverKnowledge { + id: vec_to_f(id), + nonce: vec_to_f(nonce), + nullifier_old: vec_to_f(nullifier_old), + trapdoor_old: vec_to_f(trapdoor_old), + account_old_balance: vec_to_f(account_balance_old), + path: vec_to_path(path), + withdrawal_value: vec_to_f(value), + nullifier_new: vec_to_f(nullifier_new), + trapdoor_new: vec_to_f(trapdoor_new), + commitment: vec_to_f(commitment), + }, + &mut rand::thread_rng(), + ) + } + + #[wasm_bindgen] + #[allow(clippy::too_many_arguments)] + pub fn verify( + &mut self, + id_hiding: Vec, + merkle_root: Vec, + h_nullifier_old: Vec, + h_note_new: Vec, + value: Vec, + proof: Vec, + commitment: Vec, + ) -> Result<(), JsError> { + log("Verifying WithdrawCircuit"); + + let public_input = |input: WithdrawInstance| { + let value = match input { + WithdrawInstance::IdHiding => &id_hiding, + WithdrawInstance::MerkleRoot => &merkle_root, + WithdrawInstance::HashedOldNullifier => &h_nullifier_old, + WithdrawInstance::HashedNewNote => &h_note_new, + WithdrawInstance::WithdrawalValue => &value, + WithdrawInstance::Commitment => &commitment, + }; + vec_to_f(value.clone()) + }; + + self.0.verify(&public_input, proof).map_err(JsError::from) + } +} diff --git a/crates/shielder-wasm/src/lib.rs b/crates/shielder-wasm/src/lib.rs new file mode 100644 index 00000000..31199f49 --- /dev/null +++ b/crates/shielder-wasm/src/lib.rs @@ -0,0 +1,47 @@ +#![no_std] + +extern crate alloc; + +pub mod circuits; +pub mod secrets; +pub mod wasm; + +use alloc::vec::Vec; + +use shielder_circuits::{ + consts::merkle_constants::{ARITY, NOTE_TREE_HEIGHT}, + F, +}; +use shielder_rust_sdk::conversion::bytes_to_field; +#[cfg(feature = "multithreading")] +pub use wasm_bindgen_rayon::init_thread_pool; + +fn vec_to_f(v: Vec) -> F { + bytes_to_field(v).expect("failed to convert to F") +} + +fn vec_to_path(v: Vec) -> [[F; ARITY]; NOTE_TREE_HEIGHT] { + assert_eq!( + (NOTE_TREE_HEIGHT * ARITY * F::size()), + v.len(), + "Vector length must be divisible by TREE_HEIGHT * ARITY * F::size()" + ); + + let mut result = [[F::default(); ARITY]; NOTE_TREE_HEIGHT]; + let mut iter = v.chunks_exact(F::size()); + + for row in result.iter_mut().take(NOTE_TREE_HEIGHT) { + for elem in row.iter_mut().take(ARITY) { + if let Some(chunk) = iter.next() { + *elem = F::from_bytes( + chunk + .try_into() + .unwrap_or_else(|_| panic!("should be {} bytes long", F::size())), + ) + .expect("failed to convert to F"); + } + } + } + + result +} diff --git a/crates/shielder-wasm/src/secrets.rs b/crates/shielder-wasm/src/secrets.rs new file mode 100644 index 00000000..f67c1c91 --- /dev/null +++ b/crates/shielder-wasm/src/secrets.rs @@ -0,0 +1,36 @@ +use alloc::vec::Vec; + +use shielder_rust_sdk::{ + account::secrets::{nullifier, trapdoor}, + alloy_primitives::U256, + conversion::{bytes_to_u256, u256_to_bytes}, +}; +use wasm_bindgen::prelude::wasm_bindgen; + +/// Provides a way to print debug messages from Rust code to browser console. +#[wasm_bindgen] +extern "C" { + #[wasm_bindgen(js_namespace = console)] + fn log(s: &str); +} + +type Scalar = Vec; + +#[wasm_bindgen(getter_with_clone)] // `getter_with_clone` is required for `Vec` struct fields +#[derive(Clone, Debug, Default)] +pub struct ShielderActionSecrets { + pub nullifier: Scalar, + pub trapdoor: Scalar, +} + +/// Deterministically computes `ShielderActionSecrets` from `nonce` and `id`. +/// All returned values are field elements. +#[wasm_bindgen] +pub fn get_action_secrets(id: Scalar, nonce: u32) -> ShielderActionSecrets { + let id: U256 = bytes_to_u256(id).expect("Expecting a 32-byte vector"); + + ShielderActionSecrets { + nullifier: u256_to_bytes(nullifier(id, nonce)), + trapdoor: u256_to_bytes(trapdoor(id, nonce)), + } +} diff --git a/crates/shielder-wasm/src/wasm.rs b/crates/shielder-wasm/src/wasm.rs new file mode 100644 index 00000000..5281bee1 --- /dev/null +++ b/crates/shielder-wasm/src/wasm.rs @@ -0,0 +1,43 @@ +use alloc::vec::Vec; + +use halo2_proofs::halo2curves::bn256::Fr; +use shielder_circuits::{ + consts::merkle_constants::{ARITY, NOTE_TREE_HEIGHT}, + utils::padded_hash, + F, +}; +use shielder_rust_sdk::conversion::private_key_to_field; +use wasm_bindgen::prelude::wasm_bindgen; + +use crate::vec_to_f; + +#[wasm_bindgen] +pub fn arity() -> usize { + ARITY +} + +#[wasm_bindgen] +pub fn tree_height() -> usize { + NOTE_TREE_HEIGHT +} + +#[wasm_bindgen] +pub fn padded_poseidon_hash(inputs: Vec) -> Vec { + if inputs.len() % F::size() != 0 { + panic!("Input length must be divisible by F::size()"); + } + let vec = inputs + .chunks_exact(F::size()) + .map(|v| vec_to_f(v.to_vec())) + .collect::>(); + padded_hash(&vec).to_bytes().as_slice().into() +} + +#[wasm_bindgen] +pub fn private_key_to_f(hex: &str) -> Vec { + private_key_to_field::(hex) + .unwrap() + .to_bytes() + .as_slice() + .into() +} diff --git a/crates/stress-testing/Cargo.toml b/crates/stress-testing/Cargo.toml new file mode 100644 index 00000000..a64143c7 --- /dev/null +++ b/crates/stress-testing/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "stress-testing" +version = "0.1.0" +readme = "README.md" + +edition.workspace = true +authors.workspace = true +homepage.workspace = true +license.workspace = true +categories.workspace = true +repository.workspace = true + +[dependencies] +alloy-provider = { workspace = true } +alloy-rpc-types = { workspace = true } +alloy-signer-local = { workspace = true } +anyhow = { workspace = true, default-features = true } +clap = { workspace = true, features = ["derive"] } +rand = { workspace = true } +reqwest = { workspace = true } +tokio = { workspace = true, features = ["full"] } + +shielder-circuits = { workspace = true } +shielder-relayer = { workspace = true } +shielder-rust-sdk = { workspace = true, features = ["account", "contract", "native_token", "parameter_generation"] } diff --git a/crates/stress-testing/Makefile b/crates/stress-testing/Makefile new file mode 100644 index 00000000..d48fc13b --- /dev/null +++ b/crates/stress-testing/Makefile @@ -0,0 +1,19 @@ +.PHONY: help +help: ## Displays this help + @awk 'BEGIN {FS = ":.*##"; printf "$(MAKEFILE_NAME)\nUsage:\n make \033[1;36m\033[0m\n\nTargets:\n"} /^[a-zA-Z0-9_-]+:.*?##/ { printf " \033[1;36m%-25s\033[0m %s\n", $$1, $$2 }' $(MAKEFILE_LIST) + +.PHONY: build +build: ## Build the package + @cargo build --release + +.PHONY: build-relayer-image +build-relayer-image: ## Build the relayer image + @cd ../shielder-relayer && make build && make build-image + +.PHONY: run-locally +run-locally: build build-relayer-image ## Run the stress testing in the local environment + @./local-scenario.sh + +.PHONY: run-testnet +run-testnet: build build-relayer-image ## Run the stress testing in the testnet environment + @./testnet-scenario.sh diff --git a/crates/stress-testing/README.md b/crates/stress-testing/README.md new file mode 100644 index 00000000..111c953d --- /dev/null +++ b/crates/stress-testing/README.md @@ -0,0 +1,104 @@ +# Stress testing + +Here you can find a binary that is used to check the performance of the Shielder components under high load. + +## Scenario: parallel withdrawals through the relayer + +### Description + +1. Environment setup: + - Run local anvil node (adjusted to the Aleph L2 network configuration). + - Run local relayer service. + - Endow relayer with enough funds to cover the withdrawal fees. + - Endow one address with a lot of funds (contract deployer and balance distributor). + - Deploy the Shielder contract suite. +2. Actor preparation: + - Generate a set of `N` seeds (deterministically). + - Endow each account with some funds. + - Shield the funds with the `newAccount` method. + - Prepare a relay query for each actor for a withdrawal action. +3. Pandemonium: + - Each actor starts the withdrawal action in parallel. + - The relayer processes the requests. + - The actors check the status of their withdrawals. + +Only phase 3. is executed in parallel. +All previous steps are executed sequentially (proof generation etc. is fast enough). + +### Running the test + +```bash +make run +``` + +### Possible output: + +```bash +✅ Generated actors (seeds and empty accounts) + +⏳ Endowing actors with initial balance of 400000000000000000. + ✅ Endowed address 0xB14d3c4F5FBFBCFB98af2d330000d49c95B93aA7 + ✅ Endowed address 0x735AA9fD4A3238902740E2126633B29adc0896aD + ✅ Endowed address 0x405a71aa1BE3a43102dA91119dAe73267C8334b8 + ✅ Endowed address 0x761E600F0ec99064351505A5b28F57584FD6Bf6e + ✅ Endowed address 0x77177b9884Bb7C6e6D6c955d4673A0Aec754915e + ✅ Endowed address 0xd4C85D78c5951Ee926D798ABd2Bf0bD878334d3B + ✅ Endowed address 0x9aB3496Db098fd8D6600925b5380DeB9E1C03fF3 + ✅ Endowed address 0x7535B677C8304D2C711E4E3f4aa23752ad2C30FD + ✅ Endowed address 0x680B2BA0Cef2fe2570054Fd68E79B427A7A3C35b + ✅ Endowed address 0x1AF505c471E2B579e3f0410ff7Cd6227909F8ceD +✅ Distributed tokens to actors + +WARNING: using a default value seed for generating the SRS string +⏳ Creating shielder accounts. Every account will shield 300000000000000000. + ✅ Shielded tokens for address 0xB14d3c4F5FBFBCFB98af2d330000d49c95B93aA7 + ✅ Shielded tokens for address 0x735AA9fD4A3238902740E2126633B29adc0896aD + ✅ Shielded tokens for address 0x405a71aa1BE3a43102dA91119dAe73267C8334b8 + ✅ Shielded tokens for address 0x761E600F0ec99064351505A5b28F57584FD6Bf6e + ✅ Shielded tokens for address 0x77177b9884Bb7C6e6D6c955d4673A0Aec754915e + ✅ Shielded tokens for address 0xd4C85D78c5951Ee926D798ABd2Bf0bD878334d3B + ✅ Shielded tokens for address 0x9aB3496Db098fd8D6600925b5380DeB9E1C03fF3 + ✅ Shielded tokens for address 0x7535B677C8304D2C711E4E3f4aa23752ad2C30FD + ✅ Shielded tokens for address 0x680B2BA0Cef2fe2570054Fd68E79B427A7A3C35b + ✅ Shielded tokens for address 0x1AF505c471E2B579e3f0410ff7Cd6227909F8ceD +✅ Actors have opened shielder accounts + +WARNING: using a default value seed for generating the SRS string +⏳ Preparing relay queries for actors... + ✅ Prepared relay query for actor 0 + ✅ Prepared relay query for actor 1 + ✅ Prepared relay query for actor 2 + ✅ Prepared relay query for actor 3 + ✅ Prepared relay query for actor 4 + ✅ Prepared relay query for actor 5 + ✅ Prepared relay query for actor 6 + ✅ Prepared relay query for actor 7 + ✅ Prepared relay query for actor 8 + ✅ Prepared relay query for actor 9 +✅ Prepared relay queries (proof and REST calldata) + +🎉 Entering pandemonium! 🎉 + 🚀 Actor 0 is starting the withdrawal... + 🚀 Actor 1 is starting the withdrawal... + 🚀 Actor 2 is starting the withdrawal... + 🚀 Actor 3 is starting the withdrawal... + 🚀 Actor 4 is starting the withdrawal... + 🚀 Actor 5 is starting the withdrawal... + 🚀 Actor 6 is starting the withdrawal... + 🚀 Actor 7 is starting the withdrawal... + 🚀 Actor 8 is starting the withdrawal... + 🚀 Actor 9 is starting the withdrawal... + ✅ Actor 7 succeeded! Latency: 710.880278ms. + ✅ Actor 9 succeeded! Latency: 797.164413ms. + ✅ Actor 5 succeeded! Latency: 809.240793ms. + ✅ Actor 0 succeeded! Latency: 1.270915508s. + ✅ Actor 8 succeeded! Latency: 1.365675006s. + ✅ Actor 2 succeeded! Latency: 1.370372938s. + ✅ Actor 6 succeeded! Latency: 1.858863171s. + ✅ Actor 3 succeeded! Latency: 1.909160935s. + ✅ Actor 1 succeeded! Latency: 1.909502682s. + ✅ Actor 4 succeeded! Latency: 2.353088417s. +🎉 Pandemonium is over! 🎉 + +🎉 Successful withdrawals: 10/10 +``` diff --git a/crates/stress-testing/local-scenario.sh b/crates/stress-testing/local-scenario.sh new file mode 100755 index 00000000..9e10c7fe --- /dev/null +++ b/crates/stress-testing/local-scenario.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash + +set -euo pipefail + +SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd) +ROOT_DIR="${SCRIPT_DIR}/../.." + +source "${ROOT_DIR}/tooling-e2e-tests/local_env.sh" +source "${ROOT_DIR}/tooling-e2e-tests/utils.sh" + +run() { + pushd $ROOT_DIR &>> output.log + + start_node + deploy_contracts + start_relayer + endow_accounts # only needed for relayer + + ${ROOT_DIR}/target/release/stress-testing \ + --master-seed "${DEPLOYER_PRIVATE_KEY}" \ + --node-rpc-url "${NODE_RPC_URL}" \ + --shielder "${SHIELDER_CONTRACT_ADDRESS}" \ + --relayer-url "${RELAYER_URL}/relay" \ + --relayer-address "${FEE_DESTINATION}" \ + --actor-count 10 + + popd &>> output.log +} + +trap cleanup EXIT SIGINT SIGTERM +rm -rf output.log +run diff --git a/crates/stress-testing/src/actor.rs b/crates/stress-testing/src/actor.rs new file mode 100644 index 00000000..1b923627 --- /dev/null +++ b/crates/stress-testing/src/actor.rs @@ -0,0 +1,52 @@ +use alloy_signer_local::PrivateKeySigner; +use rand::{rngs::StdRng, SeedableRng}; +use shielder_circuits::circuits::{Params, ProvingKey}; +use shielder_rust_sdk::{ + account::{call_data::NewAccountCallType, ShielderAccount}, + alloy_primitives::{Address, U256}, + contract::{ConnectionPolicy, ShielderContract::newAccountNativeCall, ShielderUser}, +}; + +pub struct Actor { + pub id: u32, + pub shielder_user: ShielderUser, + pub account: ShielderAccount, +} + +impl Actor { + pub fn new(id: u32, rpc_url: String, shielder: Address) -> Self { + let signer = PrivateKeySigner::random_with(&mut StdRng::from_seed(seed(id))); + let shielder_user = + ShielderUser::new(shielder, ConnectionPolicy::OnDemand { rpc_url, signer }); + let account = ShielderAccount::new(U256::from(id)); + Self { + id, + shielder_user, + account, + } + } + + pub fn address(&self) -> Address { + self.shielder_user.address() + } + + pub fn prepare_new_account_call( + &self, + params: &Params, + pk: &ProvingKey, + amount: U256, + ) -> newAccountNativeCall { + self.account + .prepare_call::(params, pk, amount, &()) + } +} + +fn seed(id: u32) -> [u8; 32] { + id.to_be_bytes() + .into_iter() + .cycle() + .take(32) + .collect::>() + .try_into() + .unwrap() +} diff --git a/crates/stress-testing/src/config.rs b/crates/stress-testing/src/config.rs new file mode 100644 index 00000000..33607f01 --- /dev/null +++ b/crates/stress-testing/src/config.rs @@ -0,0 +1,40 @@ +use alloy_signer_local::PrivateKeySigner; +use clap::Parser; +use shielder_rust_sdk::alloy_primitives::Address; + +#[derive(Parser)] +pub struct Config { + #[clap(long, value_parser = parsing::parse_signer)] + pub master_seed: PrivateKeySigner, + + #[clap(long)] + pub actor_count: u32, + + #[clap(long)] + pub node_rpc_url: String, + + #[clap(long, value_parser = parsing::parse_address)] + pub shielder: Address, + + #[clap(long)] + pub relayer_url: String, + + #[clap(long, value_parser = parsing::parse_address)] + pub relayer_address: Address, +} + +mod parsing { + use std::str::FromStr; + + use alloy_signer_local::PrivateKeySigner; + use anyhow::{anyhow, Result}; + use shielder_rust_sdk::alloy_primitives::Address; + + pub fn parse_address(string: &str) -> Result

{ + Address::from_str(string).map_err(|e| anyhow!(e)) + } + + pub fn parse_signer(string: &str) -> Result { + PrivateKeySigner::from_str(string).map_err(|e| anyhow!(e)) + } +} diff --git a/crates/stress-testing/src/main.rs b/crates/stress-testing/src/main.rs new file mode 100644 index 00000000..634ec2ae --- /dev/null +++ b/crates/stress-testing/src/main.rs @@ -0,0 +1,21 @@ +use anyhow::Result; +use clap::Parser; +use shielder_rust_sdk::native_token::ONE_TZERO; + +mod actor; +mod config; +mod party; +mod setup; +mod util; + +const INITIAL_BALANCE: u128 = 2 * ONE_TZERO; +const SHIELDED_BALANCE: u128 = 15 * (ONE_TZERO / 10); +const WITHDRAW_AMOUNT: u128 = ONE_TZERO; + +#[tokio::main(flavor = "multi_thread")] +async fn main() -> Result<()> { + let config = config::Config::parse(); + let actors = setup::setup_world(&config).await?; + party::enter_pandemonium(&config, actors).await?; + Ok(()) +} diff --git a/crates/stress-testing/src/party.rs b/crates/stress-testing/src/party.rs new file mode 100644 index 00000000..e91ce4bd --- /dev/null +++ b/crates/stress-testing/src/party.rs @@ -0,0 +1,125 @@ +use std::time::Instant; + +use anyhow::Result; +use shielder_circuits::{ + circuits::{Params, ProvingKey}, + consts::RANGE_PROOF_CHUNK_SIZE, + withdraw::WithdrawCircuit, +}; +use shielder_relayer::{relayer_fee, RelayQuery}; +use shielder_rust_sdk::{ + account::call_data::{MerkleProof, WithdrawCallType, WithdrawExtra}, + alloy_primitives::U256, + contract::merkle_path::get_current_merkle_path, + version::contract_version, +}; + +use crate::{actor::Actor, config::Config, util::proving_keys, WITHDRAW_AMOUNT}; + +pub async fn enter_pandemonium(config: &Config, actors: Vec) -> Result<()> { + let task_inputs = prepare_relay_queries(config, actors).await?; + println!("✅ Prepared relay queries (proof and REST calldata)\n"); + + println!("🎉 Entering pandemonium! 🎉"); + let mut handles = vec![]; + for (actor, query) in task_inputs { + let relayer = config.relayer_url.clone(); + handles.push(tokio::spawn(async move { + actor_task(actor, query, relayer).await + })); + } + + let mut successful = 0; + for handle in handles { + match handle.await? { + Ok(true) => successful += 1, + Ok(false) => (), + Err(e) => eprintln!("Error: {:?}", e), + } + } + println!("🎉 Pandemonium is over! 🎉\n"); + println!( + "🎉 Successful withdrawals: {successful}/{}", + config.actor_count + ); + + Ok(()) +} + +async fn actor_task(actor: Actor, query: RelayQuery, relayer_rpc_url: String) -> Result { + println!(" 🚀 Actor {} is starting the withdrawal...", actor.id); + + let start = Instant::now(); + let status = reqwest::Client::new() + .post(relayer_rpc_url) + .json(&query) + .send() + .await? + .status(); + let elapsed = start.elapsed(); + + if status.is_success() { + println!(" ✅ Actor {} succeeded! Latency: {elapsed:?}.", actor.id); + Ok(true) + } else { + println!( + " ❌ Actor {} failed: {status:?}. Latency: {elapsed:?}.", + actor.id + ); + Ok(false) + } +} + +async fn prepare_relay_queries<'actor>( + config: &Config, + actors: Vec, +) -> Result> { + let (params, pk) = proving_keys::>(); + let mut result = Vec::new(); + + println!("⏳ Preparing relay queries for actors..."); + for actor in actors { + let query = prepare_relay_query(config, &actor, ¶ms, &pk).await?; + result.push((actor, query)); + } + Ok(result) +} + +async fn prepare_relay_query( + config: &Config, + actor: &Actor, + params: &Params, + pk: &ProvingKey, +) -> Result { + let (merkle_root, merkle_path) = + get_current_merkle_path(U256::from(actor.id), &actor.shielder_user).await?; + let to = config.master_seed.address(); + + let calldata = actor.account.prepare_call::( + params, + pk, + U256::from(WITHDRAW_AMOUNT), + &WithdrawExtra { + merkle_proof: MerkleProof { + root: merkle_root, + path: merkle_path, + }, + to, + relayer_address: config.relayer_address, + relayer_fee: relayer_fee(), + contract_version: contract_version(), + }, + ); + + let query = RelayQuery { + id_hiding: calldata.idHiding, + amount: U256::from(WITHDRAW_AMOUNT), + withdraw_address: to, + merkle_root, + nullifier_hash: calldata.oldNullifierHash, + new_note: calldata.newNote, + proof: calldata.proof, + }; + println!(" ✅ Prepared relay query for actor {}", actor.id); + Ok(query) +} diff --git a/crates/stress-testing/src/setup.rs b/crates/stress-testing/src/setup.rs new file mode 100644 index 00000000..b8925e8f --- /dev/null +++ b/crates/stress-testing/src/setup.rs @@ -0,0 +1,94 @@ +use alloy_provider::{ + fillers::WalletFiller, + network::{EthereumWallet, TransactionBuilder}, + Provider, ProviderBuilder, +}; +use alloy_rpc_types::TransactionRequest; +use alloy_signer_local::PrivateKeySigner; +use anyhow::{anyhow, Result}; +use shielder_circuits::new_account::NewAccountCircuit; +use shielder_rust_sdk::{ + account::ShielderAction, + alloy_primitives::U256, + contract::{ + call_type::Call, events::get_event, providers::create_simple_provider, + ShielderContract::NewAccountNative, + }, +}; + +use crate::{actor::Actor, config::Config, util::proving_keys, INITIAL_BALANCE, SHIELDED_BALANCE}; + +pub async fn setup_world(config: &Config) -> Result> { + let mut actors = generate_actors(config); + println!("✅ Generated actors (seeds and empty accounts)\n"); + + distribute_tokens(config, &actors).await?; + println!("✅ Distributed tokens to actors\n"); + + shield_tokens(config, &mut actors).await?; + println!("✅ Actors have opened shielder accounts\n"); + + Ok(actors) +} + +fn generate_actors(config: &Config) -> Vec { + (0..config.actor_count) + .map(|id| Actor::new(id, config.node_rpc_url.clone(), config.shielder)) + .collect() +} + +async fn prepare_provider(node_rpc_url: &str, signer: PrivateKeySigner) -> Result { + ProviderBuilder::new() + .with_recommended_fillers() + .filler(WalletFiller::new(EthereumWallet::from(signer))) + .on_builtin(node_rpc_url) + .await + .map_err(|e| anyhow!(e)) +} + +async fn distribute_tokens(config: &Config, actors: &[Actor]) -> Result<()> { + let provider = prepare_provider(&config.node_rpc_url, config.master_seed.clone()).await?; + + let tx = TransactionRequest::default() + .with_from(config.master_seed.address()) + .with_value(U256::from(INITIAL_BALANCE)); + + println!("⏳ Endowing actors with initial balance of {INITIAL_BALANCE}."); + for actor in actors { + provider + .send_transaction(tx.clone().with_to(actor.address())) + .await? + .watch() + .await?; + println!(" ✅ Endowed address {}", actor.address()); + } + Ok(()) +} + +async fn shield_tokens(config: &Config, actors: &mut [Actor]) -> Result<()> { + let (params, pk) = proving_keys::>(); + let shielded_amount = U256::from(SHIELDED_BALANCE); + let provider = create_simple_provider(&config.node_rpc_url).await?; + + println!("⏳ Creating shielder accounts. Every account will shield {SHIELDED_BALANCE}."); + for actor in actors { + let call = actor.prepare_new_account_call(¶ms, &pk, shielded_amount); + + let (tx_hash, block_hash) = actor + .shielder_user + .create_new_account_native::(call, shielded_amount) + .await?; + + let new_account_event = + get_event::(&provider, tx_hash, block_hash).await?; + + actor.account.register_action(ShielderAction::new_account( + shielded_amount, + new_account_event.newNoteIndex, + tx_hash, + )); + + println!(" ✅ Shielded tokens for address {}", actor.address()); + } + Ok(()) +} diff --git a/crates/stress-testing/src/util.rs b/crates/stress-testing/src/util.rs new file mode 100644 index 00000000..31f4b514 --- /dev/null +++ b/crates/stress-testing/src/util.rs @@ -0,0 +1,11 @@ +use shielder_circuits::{ + circuits::{Params, ProvingKey}, + generate_keys_with_min_k, generate_setup_params, Circuit, F, MAX_K, +}; +use shielder_rust_sdk::parameter_generation; + +pub fn proving_keys + Default>() -> (Params, ProvingKey) { + let params = generate_setup_params(MAX_K, &mut parameter_generation::rng()); + let (params, _, pk, _) = generate_keys_with_min_k::(params).unwrap(); + (params, pk) +} diff --git a/crates/stress-testing/testnet-scenario.sh b/crates/stress-testing/testnet-scenario.sh new file mode 100755 index 00000000..4b612e5d --- /dev/null +++ b/crates/stress-testing/testnet-scenario.sh @@ -0,0 +1,66 @@ +#!/usr/bin/env bash + +set -euo pipefail + +SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd) +ROOT_DIR="${SCRIPT_DIR}/../.." + +# ==================================================================================================================== # +# ENVIRONMENT # +# ==================================================================================================================== # + +# ======================== Relayer configuration ======================== + +NODE_RPC_URL="https://rpc.alephzero-testnet.gelato.digital" +export NODE_RPC_URL + +RELAYER_PORT=4141 +export RELAYER_PORT +RELAYER_URL="http://localhost:${RELAYER_PORT}" +export RELAYER_URL + +NONCE_POLICY=caching +export NONCE_POLICY +DRY_RUNNING=optimistic +export DRY_RUNNING +RELAY_COUNT_FOR_RECHARGE=10 +export RELAY_COUNT_FOR_RECHARGE + +# ======================== Accounts ======================== +DEPLOYER_PRIVATE_KEY= +export DEPLOYER_PRIVATE_KEY + +FEE_DESTINATION_KEY= +export FEE_DESTINATION_KEY +FEE_DESTINATION= +export FEE_DESTINATION + +RELAYER_SIGNING_KEYS= +export RELAYER_SIGNING_KEYS + +# ==================================================================================================================== # +# SCENARIO # +# ==================================================================================================================== # + +source "${ROOT_DIR}/tooling-e2e-tests/utils.sh" + +run() { + pushd $ROOT_DIR &>> output.log + + deploy_contracts + start_relayer + + ${ROOT_DIR}/target/release/stress-testing \ + --master-seed "${DEPLOYER_PRIVATE_KEY}" \ + --node-rpc-url "${NODE_RPC_URL}" \ + --shielder "${SHIELDER_CONTRACT_ADDRESS}" \ + --relayer-url "${RELAYER_URL}/relay" \ + --relayer-address "${FEE_DESTINATION}" \ + --actor-count 12 + + popd &>> output.log +} + +trap cleanup EXIT SIGINT SIGTERM +rm -rf output.log +run diff --git a/crates/test-ts-conversions/Cargo.toml b/crates/test-ts-conversions/Cargo.toml new file mode 100644 index 00000000..a90b64cb --- /dev/null +++ b/crates/test-ts-conversions/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "test-ts-conversions" +version = "0.1.0" +edition.workspace = true +authors.workspace = true +homepage.workspace = true +license.workspace = true +categories.workspace = true +repository.workspace = true + +[dependencies] +clap = { workspace = true, features = ["derive"] } +halo2_proofs = { workspace = true } +shielder-circuits = { workspace = true } +shielder-rust-sdk = { workspace = true, features = ["account", "conversion", "parameter_generation"] } diff --git a/crates/test-ts-conversions/src/main.rs b/crates/test-ts-conversions/src/main.rs new file mode 100644 index 00000000..a7cd8029 --- /dev/null +++ b/crates/test-ts-conversions/src/main.rs @@ -0,0 +1,85 @@ +use std::error::Error; + +use clap::{Parser, Subcommand}; +use halo2_proofs::halo2curves::{bn256::Fr, ff::PrimeField}; +use shielder_circuits::utils::padded_hash; +use shielder_rust_sdk::{ + account::secrets::{nullifier, trapdoor}, + conversion::{bytes_to_field, bytes_to_u256}, +}; + +#[derive(Parser)] +struct Args { + #[command(subcommand)] + command: Commands, +} + +#[derive(Subcommand)] +enum Commands { + PaddedPoseidonHashAgreesWithRust { + #[clap(long, required = true, value_delimiter = ',')] + hashed_tuple: Vec, + + #[clap(long, required = true, value_delimiter = ',')] + expected_hash: Vec, + }, + U128EqualsBytes { + number: u128, + #[clap(value_delimiter = ',')] + bytes: Vec, + }, + WasmSecretsAgreeWithRust { + #[clap(long, required = true, value_delimiter = ',')] + seed: Vec, + + #[clap(long, required = true)] + nonce: u32, + + #[clap(long, required = true, value_delimiter = ',')] + expected_nullifier: Vec, + + #[clap(long, required = true, value_delimiter = ',')] + expected_trapdoor: Vec, + }, +} + +fn main() -> Result<(), Box> { + let args = Args::parse(); + match args.command { + Commands::PaddedPoseidonHashAgreesWithRust { + hashed_tuple, + expected_hash, + } => { + assert!(hashed_tuple.len() % 32 == 0); + let hashed_tuple: Vec = hashed_tuple + .chunks(32) + .map(|chunk| bytes_to_field(chunk.to_vec())) + .collect::, _>>()?; + let actual_hash = padded_hash(&hashed_tuple); + + let expected_hash: Fr = bytes_to_field(expected_hash)?; + + assert_eq!(expected_hash, actual_hash); + } + + Commands::U128EqualsBytes { number, bytes } => { + assert_eq!(Fr::from_u128(number), bytes_to_field(bytes)?); + } + + Commands::WasmSecretsAgreeWithRust { + seed, + nonce, + expected_nullifier, + expected_trapdoor, + } => { + let seed = bytes_to_u256(seed)?; + + let expected_nullifier = bytes_to_u256(expected_nullifier)?; + let expected_trapdoor = bytes_to_u256(expected_trapdoor)?; + + assert_eq!(expected_nullifier, nullifier(seed, nonce)); + assert_eq!(expected_trapdoor, trapdoor(seed, nonce)); + } + }; + Ok(()) +} diff --git a/foundry.toml b/foundry.toml new file mode 100644 index 00000000..02181451 --- /dev/null +++ b/foundry.toml @@ -0,0 +1,18 @@ +# Full reference https://github.com/foundry-rs/foundry/tree/master/crates/config + +[profile.default] +auto_detect_solc = true +block_timestamp = 1_680_220_800 # March 31, 2023 at 00:00 GMT +bytecode_hash = "none" +evm_version = "shanghai" +fuzz = { runs = 1_000 } +gas_reports = ["*"] +optimizer = true +via-ir = true +out = "artifacts" +script = "scripts" +src = "contracts" +test = "test" + +[rpc_endpoints] +anvil = "http://localhost:8545" diff --git a/logo.png b/logo.png new file mode 100644 index 00000000..77674160 Binary files /dev/null and b/logo.png differ diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..ec77c9a9 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,4952 @@ +{ + "name": "zkOS", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "zkOS", + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "@openzeppelin/contracts": "=5.0.2", + "@openzeppelin/contracts-upgradeable": "=5.0.2", + "@uniswap/permit2": "github:Uniswap/permit2#cc56ad0f3439c502c246fc5cfcc3db92bb8b7219", + "solmate": "github:transmissions11/solmate#8d910d876f51c3b2585c9109409d601f600e68e1" + }, + "devDependencies": { + "@safe-global/protocol-kit": "^3.0.0", + "@safe-global/safe-core-sdk-types": "^4.0.0", + "child_process": "^1.0.2", + "dotenv": "^16.3.1", + "forge-std": "github:foundry-rs/forge-std#v1.8.1", + "prettier": "^3.2.5", + "prettier-plugin-solidity": "^1.3.1", + "solhint-community": "^3.7.0", + "solhint-plugin-prettier": "^0.1.0" + } + }, + "node_modules/@adraffy/ens-normalize": { + "version": "1.10.1", + "dev": true, + "license": "MIT" + }, + "node_modules/@babel/code-frame": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/highlight": "^7.24.7", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.24.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.24.7", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@ethereumjs/common": { + "version": "2.6.5", + "dev": true, + "license": "MIT", + "dependencies": { + "crc-32": "^1.2.0", + "ethereumjs-util": "^7.1.5" + } + }, + "node_modules/@ethereumjs/rlp": { + "version": "4.0.1", + "dev": true, + "license": "MPL-2.0", + "bin": { + "rlp": "bin/rlp" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@ethereumjs/tx": { + "version": "3.5.2", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "@ethereumjs/common": "^2.6.4", + "ethereumjs-util": "^7.1.5" + } + }, + "node_modules/@ethereumjs/util": { + "version": "8.1.0", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "@ethereumjs/rlp": "^4.0.1", + "ethereum-cryptography": "^2.0.0", + "micro-ftch": "^0.3.1" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@ethereumjs/util/node_modules/@noble/curves": { + "version": "1.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.4.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@ethereumjs/util/node_modules/ethereum-cryptography": { + "version": "2.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/curves": "1.4.0", + "@noble/hashes": "1.4.0", + "@scure/bip32": "1.4.0", + "@scure/bip39": "1.3.0" + } + }, + "node_modules/@ethersproject/abi": { + "version": "5.7.0", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@ethersproject/abstract-provider": { + "version": "5.7.0", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/networks": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/web": "^5.7.0" + } + }, + "node_modules/@ethersproject/abstract-signer": { + "version": "5.7.0", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0" + } + }, + "node_modules/@ethersproject/address": { + "version": "5.7.0", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/rlp": "^5.7.0" + } + }, + "node_modules/@ethersproject/base64": { + "version": "5.7.0", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bytes": "^5.7.0" + } + }, + "node_modules/@ethersproject/bignumber": { + "version": "5.7.0", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "bn.js": "^5.2.1" + } + }, + "node_modules/@ethersproject/bytes": { + "version": "5.7.0", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/constants": { + "version": "5.7.0", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bignumber": "^5.7.0" + } + }, + "node_modules/@ethersproject/hash": { + "version": "5.7.0", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/base64": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@ethersproject/keccak256": { + "version": "5.7.0", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "js-sha3": "0.8.0" + } + }, + "node_modules/@ethersproject/logger": { + "version": "5.7.0", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT" + }, + "node_modules/@ethersproject/networks": { + "version": "5.7.1", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/properties": { + "version": "5.7.0", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/rlp": { + "version": "5.7.0", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/signing-key": { + "version": "5.7.0", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "bn.js": "^5.2.1", + "elliptic": "6.5.4", + "hash.js": "1.1.7" + } + }, + "node_modules/@ethersproject/strings": { + "version": "5.7.0", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/transactions": { + "version": "5.7.0", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/rlp": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0" + } + }, + "node_modules/@ethersproject/web": { + "version": "5.7.1", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@ethersproject/base64": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@noble/curves": { + "version": "1.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.3.2" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/curves/node_modules/@noble/hashes": { + "version": "1.3.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/hashes": { + "version": "1.4.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@openzeppelin/contracts": { + "version": "5.0.2", + "license": "MIT" + }, + "node_modules/@openzeppelin/contracts-upgradeable": { + "version": "5.0.2", + "license": "MIT", + "peerDependencies": { + "@openzeppelin/contracts": "5.0.2" + } + }, + "node_modules/@prettier/sync": { + "version": "0.3.0", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/prettier/prettier-synchronized?sponsor=1" + }, + "peerDependencies": { + "prettier": "^3.0.0" + } + }, + "node_modules/@safe-global/protocol-kit": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "^1.3.3", + "@safe-global/safe-deployments": "^1.36.0", + "ethereumjs-util": "^7.1.5", + "ethers": "^6.7.1", + "semver": "^7.5.4", + "web3": "^1.10.3", + "web3-core": "^1.10.3", + "web3-utils": "^1.10.3" + } + }, + "node_modules/@safe-global/protocol-kit/node_modules/semver": { + "version": "7.6.2", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@safe-global/safe-core-sdk-types": { + "version": "4.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@safe-global/safe-deployments": "^1.36.0", + "ethers": "^6.7.1", + "web3-core": "^1.10.3", + "web3-utils": "^1.10.3" + } + }, + "node_modules/@safe-global/safe-deployments": { + "version": "1.37.0", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.6.0" + } + }, + "node_modules/@safe-global/safe-deployments/node_modules/semver": { + "version": "7.6.2", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@scure/base": { + "version": "1.1.7", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip32": { + "version": "1.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/curves": "~1.4.0", + "@noble/hashes": "~1.4.0", + "@scure/base": "~1.1.6" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip32/node_modules/@noble/curves": { + "version": "1.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.4.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip39": { + "version": "1.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "~1.4.0", + "@scure/base": "~1.1.6" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@szmarczak/http-timer": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "defer-to-connect": "^2.0.1" + }, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/@types/bn.js": { + "version": "5.1.5", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/cacheable-request": { + "version": "6.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-cache-semantics": "*", + "@types/keyv": "^3.1.4", + "@types/node": "*", + "@types/responselike": "^1.0.0" + } + }, + "node_modules/@types/http-cache-semantics": { + "version": "4.0.4", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/keyv": { + "version": "3.1.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "20.14.8", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/pbkdf2": { + "version": "3.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/responselike": { + "version": "1.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/secp256k1": { + "version": "4.0.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@uniswap/permit2": { + "version": "1.0.0", + "resolved": "git+ssh://git@github.com/Uniswap/permit2.git#cc56ad0f3439c502c246fc5cfcc3db92bb8b7219", + "integrity": "sha512-XzfhRXtbw27teTj3QLsdRmQJwxpZTGZh/Cx5zvAOkGsD7zmIJaG5QdD2KCcjmt5AGonn0aVUqQF3LEIv5+oE+g==", + "license": "MIT" + }, + "node_modules/abortcontroller-polyfill": { + "version": "1.7.5", + "dev": true, + "license": "MIT" + }, + "node_modules/accepts": { + "version": "1.3.8", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/aes-js": { + "version": "4.0.0-beta.5", + "dev": true, + "license": "MIT" + }, + "node_modules/ajv": { + "version": "6.12.6", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/antlr4": { + "version": "4.13.1", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=16" + } + }, + "node_modules/antlr4ts": { + "version": "0.5.0-alpha.4", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/argparse": { + "version": "2.0.1", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "dev": true, + "license": "MIT" + }, + "node_modules/asn1": { + "version": "0.2.6", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "node_modules/assert-plus": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/ast-parents": { + "version": "0.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/astral-regex": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/async-limiter": { + "version": "1.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "dev": true, + "license": "MIT" + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "dev": true, + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/aws-sign2": { + "version": "0.7.0", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "*" + } + }, + "node_modules/aws4": { + "version": "1.13.0", + "dev": true, + "license": "MIT" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/base-x": { + "version": "3.0.9", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/bcrypt-pbkdf/node_modules/tweetnacl": { + "version": "0.14.5", + "dev": true, + "license": "Unlicense" + }, + "node_modules/blakejs": { + "version": "1.2.1", + "dev": true, + "license": "MIT" + }, + "node_modules/bluebird": { + "version": "3.7.2", + "dev": true, + "license": "MIT" + }, + "node_modules/bn.js": { + "version": "5.2.1", + "dev": true, + "license": "MIT" + }, + "node_modules/body-parser": { + "version": "1.20.2", + "dev": true, + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/body-parser/node_modules/qs": { + "version": "6.11.0", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/brorand": { + "version": "1.1.0", + "dev": true, + "license": "MIT" + }, + "node_modules/browserify-aes": { + "version": "1.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/bs58": { + "version": "4.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "base-x": "^3.0.2" + } + }, + "node_modules/bs58check": { + "version": "2.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "bs58": "^4.0.0", + "create-hash": "^1.1.0", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/buffer-to-arraybuffer": { + "version": "0.0.5", + "dev": true, + "license": "MIT" + }, + "node_modules/buffer-xor": { + "version": "1.0.3", + "dev": true, + "license": "MIT" + }, + "node_modules/bufferutil": { + "version": "4.0.8", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.7", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caseless": { + "version": "0.12.0", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/chalk": { + "version": "2.4.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/child_process": { + "version": "1.0.2", + "dev": true, + "license": "ISC" + }, + "node_modules/chownr": { + "version": "1.1.4", + "dev": true, + "license": "ISC" + }, + "node_modules/cids": { + "version": "0.7.5", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer": "^5.5.0", + "class-is": "^1.1.0", + "multibase": "~0.6.0", + "multicodec": "^1.0.0", + "multihashes": "~0.4.15" + }, + "engines": { + "node": ">=4.0.0", + "npm": ">=3.0.0" + } + }, + "node_modules/cids/node_modules/buffer": { + "version": "5.7.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/cids/node_modules/multicodec": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer": "^5.6.0", + "varint": "^5.0.0" + } + }, + "node_modules/cipher-base": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/class-is": { + "version": "1.1.0", + "dev": true, + "license": "MIT" + }, + "node_modules/clone-response": { + "version": "1.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-response": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/clone-response/node_modules/mimic-response": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "dev": true, + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-hash": { + "version": "2.5.2", + "dev": true, + "license": "ISC", + "dependencies": { + "cids": "^0.7.1", + "multicodec": "^0.5.5", + "multihashes": "^0.4.15" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "dev": true, + "license": "MIT" + }, + "node_modules/cors": { + "version": "2.8.5", + "dev": true, + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/cosmiconfig": { + "version": "8.3.6", + "dev": true, + "license": "MIT", + "dependencies": { + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0", + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/crc-32": { + "version": "1.2.2", + "dev": true, + "license": "Apache-2.0", + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/create-hash": { + "version": "1.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "node_modules/create-hmac": { + "version": "1.1.7", + "dev": true, + "license": "MIT", + "dependencies": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "node_modules/cross-fetch": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "node-fetch": "^2.6.12" + } + }, + "node_modules/d": { + "version": "1.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "es5-ext": "^0.10.64", + "type": "^2.7.2" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/dashdash": { + "version": "1.14.1", + "dev": true, + "license": "MIT", + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/decode-uri-component": { + "version": "0.2.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decompress-response/node_modules/mimic-response": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/defer-to-connect": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/dom-walk": { + "version": "0.1.2", + "dev": true + }, + "node_modules/dotenv": { + "version": "16.4.5", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/ecc-jsbn": { + "version": "0.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "dev": true, + "license": "MIT" + }, + "node_modules/elliptic": { + "version": "6.5.4", + "dev": true, + "license": "MIT", + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/elliptic/node_modules/bn.js": { + "version": "4.12.0", + "dev": true, + "license": "MIT" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "dev": true, + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es5-ext": { + "version": "0.10.64", + "dev": true, + "hasInstallScript": true, + "license": "ISC", + "dependencies": { + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "esniff": "^2.0.1", + "next-tick": "^1.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/es6-iterator": { + "version": "2.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/es6-promise": { + "version": "4.2.8", + "dev": true, + "license": "MIT" + }, + "node_modules/es6-symbol": { + "version": "3.1.4", + "dev": true, + "license": "ISC", + "dependencies": { + "d": "^1.0.2", + "ext": "^1.7.0" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "dev": true, + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/esniff": { + "version": "2.0.1", + "dev": true, + "license": "ISC", + "dependencies": { + "d": "^1.0.1", + "es5-ext": "^0.10.62", + "event-emitter": "^0.3.5", + "type": "^2.7.2" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eth-ens-namehash": { + "version": "2.0.8", + "dev": true, + "license": "ISC", + "dependencies": { + "idna-uts46-hx": "^2.3.1", + "js-sha3": "^0.5.7" + } + }, + "node_modules/eth-ens-namehash/node_modules/js-sha3": { + "version": "0.5.7", + "dev": true, + "license": "MIT" + }, + "node_modules/eth-lib": { + "version": "0.1.29", + "dev": true, + "license": "MIT", + "dependencies": { + "bn.js": "^4.11.6", + "elliptic": "^6.4.0", + "nano-json-stream-parser": "^0.1.2", + "servify": "^0.1.12", + "ws": "^3.0.0", + "xhr-request-promise": "^0.1.2" + } + }, + "node_modules/eth-lib/node_modules/bn.js": { + "version": "4.12.0", + "dev": true, + "license": "MIT" + }, + "node_modules/eth-lib/node_modules/safe-buffer": { + "version": "5.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/eth-lib/node_modules/ws": { + "version": "3.3.3", + "dev": true, + "license": "MIT", + "dependencies": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + }, + "node_modules/ethereum-bloom-filters": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "^1.4.0" + } + }, + "node_modules/ethereum-cryptography": { + "version": "0.1.3", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "node_modules/ethereumjs-util": { + "version": "7.1.5", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "rlp": "^2.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/ethers": { + "version": "6.13.1", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/ethers-io/" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "license": "MIT", + "dependencies": { + "@adraffy/ens-normalize": "1.10.1", + "@noble/curves": "1.2.0", + "@noble/hashes": "1.3.2", + "@types/node": "18.15.13", + "aes-js": "4.0.0-beta.5", + "tslib": "2.4.0", + "ws": "8.17.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/ethers/node_modules/@noble/hashes": { + "version": "1.3.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/ethers/node_modules/@types/node": { + "version": "18.15.13", + "dev": true, + "license": "MIT" + }, + "node_modules/ethers/node_modules/tslib": { + "version": "2.4.0", + "dev": true, + "license": "0BSD" + }, + "node_modules/ethjs-unit": { + "version": "0.1.6", + "dev": true, + "license": "MIT", + "dependencies": { + "bn.js": "4.11.6", + "number-to-bn": "1.7.0" + }, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/ethjs-unit/node_modules/bn.js": { + "version": "4.11.6", + "dev": true, + "license": "MIT" + }, + "node_modules/event-emitter": { + "version": "0.3.5", + "dev": true, + "license": "MIT", + "dependencies": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.4", + "dev": true, + "license": "MIT" + }, + "node_modules/evp_bytestokey": { + "version": "1.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/express": { + "version": "4.19.2", + "dev": true, + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.2", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.6.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express/node_modules/cookie": { + "version": "0.6.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/express/node_modules/qs": { + "version": "6.11.0", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ext": { + "version": "1.7.0", + "dev": true, + "license": "ISC", + "dependencies": { + "type": "^2.7.2" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/extsprintf": { + "version": "1.3.0", + "dev": true, + "engines": [ + "node >=0.6.0" + ], + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-diff": { + "version": "1.3.0", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "dev": true, + "license": "MIT" + }, + "node_modules/finalhandler": { + "version": "1.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/for-each": { + "version": "0.3.3", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/forever-agent": { + "version": "0.6.1", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "*" + } + }, + "node_modules/forge-std": { + "version": "1.7.6", + "resolved": "git+ssh://git@github.com/foundry-rs/forge-std.git#bb4ceea94d6f10eeb5b41dc2391c6c8bf8e734ef", + "dev": true, + "license": "(Apache-2.0 OR MIT)" + }, + "node_modules/forwarded": { + "version": "0.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-minipass": { + "version": "1.2.7", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^2.6.0" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/function-bind": { + "version": "1.1.2", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/getpass": { + "version": "0.1.7", + "dev": true, + "license": "MIT", + "dependencies": { + "assert-plus": "^1.0.0" + } + }, + "node_modules/global": { + "version": "4.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "min-document": "^2.19.0", + "process": "^0.11.10" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "dev": true, + "license": "ISC" + }, + "node_modules/har-schema": { + "version": "2.0.0", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=4" + } + }, + "node_modules/har-validator": { + "version": "5.1.5", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hash-base": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/hash-base/node_modules/readable-stream": { + "version": "3.6.2", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/hash.js": { + "version": "1.1.7", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hmac-drbg": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.1.1", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/http-errors": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-https": { + "version": "1.0.0", + "dev": true, + "license": "ISC" + }, + "node_modules/http-signature": { + "version": "1.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + }, + "engines": { + "node": ">=0.8", + "npm": ">=1.3.7" + } + }, + "node_modules/http2-wrapper": { + "version": "2.2.1", + "dev": true, + "license": "MIT", + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.2.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/idna-uts46-hx": { + "version": "2.3.1", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "2.1.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/ignore": { + "version": "5.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "dev": true, + "license": "ISC" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-arguments": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "dev": true, + "license": "MIT" + }, + "node_modules/is-callable": { + "version": "1.2.7", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-function": { + "version": "1.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/is-generator-function": { + "version": "1.0.10", + "dev": true, + "license": "MIT", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-hex-prefixed": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.13", + "dev": true, + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/isstream": { + "version": "0.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/js-sha3": { + "version": "0.8.0", + "dev": true, + "license": "MIT" + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsbn": { + "version": "0.1.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema": { + "version": "0.4.0", + "dev": true, + "license": "(AFL-2.1 OR BSD-3-Clause)" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "dev": true, + "license": "ISC" + }, + "node_modules/jsonfile": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsprim": { + "version": "1.4.2", + "dev": true, + "license": "MIT", + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/keccak": { + "version": "3.0.4", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/keccak/node_modules/readable-stream": { + "version": "3.6.2", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash": { + "version": "4.17.21", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.truncate": { + "version": "4.4.2", + "dev": true, + "license": "MIT" + }, + "node_modules/lowercase-keys": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/md5.js": { + "version": "1.3.5", + "dev": true, + "license": "MIT", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/methods": { + "version": "1.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micro-ftch": { + "version": "0.3.1", + "dev": true, + "license": "MIT" + }, + "node_modules/mime": { + "version": "1.6.0", + "dev": true, + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/min-document": { + "version": "2.19.0", + "dev": true, + "dependencies": { + "dom-walk": "^0.1.0" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "dev": true, + "license": "ISC" + }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/minimist": { + "version": "1.2.8", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "2.9.0", + "dev": true, + "license": "ISC", + "dependencies": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "node_modules/minizlib": { + "version": "1.3.3", + "dev": true, + "license": "MIT", + "dependencies": { + "minipass": "^2.9.0" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/mkdirp-promise": { + "version": "5.0.1", + "dev": true, + "license": "ISC", + "dependencies": { + "mkdirp": "*" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mock-fs": { + "version": "4.14.0", + "dev": true, + "license": "MIT" + }, + "node_modules/multibase": { + "version": "0.6.1", + "dev": true, + "license": "MIT", + "dependencies": { + "base-x": "^3.0.8", + "buffer": "^5.5.0" + } + }, + "node_modules/multibase/node_modules/buffer": { + "version": "5.7.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/multicodec": { + "version": "0.5.7", + "dev": true, + "license": "MIT", + "dependencies": { + "varint": "^5.0.0" + } + }, + "node_modules/multihashes": { + "version": "0.4.21", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer": "^5.5.0", + "multibase": "^0.7.0", + "varint": "^5.0.0" + } + }, + "node_modules/multihashes/node_modules/buffer": { + "version": "5.7.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/multihashes/node_modules/multibase": { + "version": "0.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "base-x": "^3.0.8", + "buffer": "^5.5.0" + } + }, + "node_modules/nano-json-stream-parser": { + "version": "0.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "0.6.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/next-tick": { + "version": "1.1.0", + "dev": true, + "license": "ISC" + }, + "node_modules/node-addon-api": { + "version": "2.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-gyp-build": { + "version": "4.8.1", + "dev": true, + "license": "MIT", + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/number-to-bn": { + "version": "1.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "bn.js": "4.11.6", + "strip-hex-prefix": "1.0.0" + }, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/number-to-bn/node_modules/bn.js": { + "version": "4.11.6", + "dev": true, + "license": "MIT" + }, + "node_modules/oauth-sign": { + "version": "0.9.0", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "*" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/oboe": { + "version": "2.1.5", + "dev": true, + "license": "BSD", + "dependencies": { + "http-https": "^1.0.0" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/p-cancelable": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.20" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-headers": { + "version": "2.0.5", + "dev": true, + "license": "MIT" + }, + "node_modules/parse-json": { + "version": "5.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "dev": true, + "license": "MIT" + }, + "node_modules/path-type": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/pbkdf2": { + "version": "3.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/performance-now": { + "version": "2.1.0", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.0.1", + "dev": true, + "license": "ISC" + }, + "node_modules/pluralize": { + "version": "8.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/prettier": { + "version": "3.3.2", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/prettier-plugin-solidity": { + "version": "1.3.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@solidity-parser/parser": "^0.17.0", + "semver": "^7.5.4", + "solidity-comments-extractor": "^0.0.8" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "prettier": ">=2.3.0" + } + }, + "node_modules/prettier-plugin-solidity/node_modules/@solidity-parser/parser": { + "version": "0.17.0", + "dev": true, + "license": "MIT" + }, + "node_modules/prettier-plugin-solidity/node_modules/semver": { + "version": "7.6.2", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/process": { + "version": "0.11.10", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "dev": true, + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/psl": { + "version": "1.9.0", + "dev": true, + "license": "MIT" + }, + "node_modules/punycode": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/query-string": { + "version": "5.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "decode-uri-component": "^0.2.0", + "object-assign": "^4.1.0", + "strict-uri-encode": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/quick-lru": { + "version": "5.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "dev": true, + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/request": { + "version": "2.88.2", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/request/node_modules/form-data": { + "version": "2.3.3", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/request/node_modules/qs": { + "version": "6.5.3", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/request/node_modules/uuid": { + "version": "3.4.0", + "dev": true, + "license": "MIT", + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/resolve-alpn": { + "version": "1.2.1", + "dev": true, + "license": "MIT" + }, + "node_modules/ripemd160": { + "version": "2.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "node_modules/rlp": { + "version": "2.2.7", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "bn.js": "^5.2.0" + }, + "bin": { + "rlp": "bin/rlp" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/scrypt-js": { + "version": "3.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/secp256k1": { + "version": "4.0.3", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "elliptic": "^6.5.4", + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/send": { + "version": "0.18.0", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/serve-static": { + "version": "1.15.0", + "dev": true, + "license": "MIT", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/servify": { + "version": "0.1.12", + "dev": true, + "license": "MIT", + "dependencies": { + "body-parser": "^1.16.0", + "cors": "^2.8.1", + "express": "^4.14.0", + "request": "^2.79.0", + "xhr": "^2.3.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "dev": true, + "license": "MIT" + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "dev": true, + "license": "ISC" + }, + "node_modules/sha.js": { + "version": "2.4.11", + "dev": true, + "license": "(MIT AND BSD-3-Clause)", + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + }, + "bin": { + "sha.js": "bin.js" + } + }, + "node_modules/side-channel": { + "version": "1.0.6", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/simple-concat": { + "version": "1.0.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/simple-get": { + "version": "2.8.2", + "dev": true, + "license": "MIT", + "dependencies": { + "decompress-response": "^3.3.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/simple-get/node_modules/decompress-response": { + "version": "3.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-response": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/simple-get/node_modules/mimic-response": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/slice-ansi": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/slice-ansi/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/solhint-community": { + "version": "3.7.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@solidity-parser/parser": "^0.16.0", + "ajv": "^6.12.6", + "antlr4": "^4.11.0", + "ast-parents": "^0.0.1", + "chalk": "^4.1.2", + "commander": "^11.1.0", + "cosmiconfig": "^8.0.0", + "fast-diff": "^1.2.0", + "glob": "^8.0.3", + "ignore": "^5.2.4", + "js-yaml": "^4.1.0", + "lodash": "^4.17.21", + "pluralize": "^8.0.0", + "semver": "^6.3.0", + "strip-ansi": "^6.0.1", + "table": "^6.8.1", + "text-table": "^0.2.0" + }, + "bin": { + "solhint": "solhint.js" + }, + "optionalDependencies": { + "prettier": "^2.8.3" + } + }, + "node_modules/solhint-community/node_modules/@solidity-parser/parser": { + "version": "0.16.2", + "dev": true, + "license": "MIT", + "dependencies": { + "antlr4ts": "^0.5.0-alpha.4" + } + }, + "node_modules/solhint-community/node_modules/ansi-regex": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/solhint-community/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/solhint-community/node_modules/brace-expansion": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/solhint-community/node_modules/chalk": { + "version": "4.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/solhint-community/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/solhint-community/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "license": "MIT" + }, + "node_modules/solhint-community/node_modules/commander": { + "version": "11.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + } + }, + "node_modules/solhint-community/node_modules/glob": { + "version": "8.1.0", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/solhint-community/node_modules/has-flag": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/solhint-community/node_modules/minimatch": { + "version": "5.1.6", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/solhint-community/node_modules/prettier": { + "version": "2.8.8", + "dev": true, + "license": "MIT", + "optional": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/solhint-community/node_modules/strip-ansi": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/solhint-community/node_modules/supports-color": { + "version": "7.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/solhint-plugin-prettier": { + "version": "0.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@prettier/sync": "^0.3.0", + "prettier-linter-helpers": "^1.0.0" + }, + "peerDependencies": { + "prettier": "^3.0.0", + "prettier-plugin-solidity": "^1.0.0" + } + }, + "node_modules/solidity-comments-extractor": { + "version": "0.0.8", + "dev": true, + "license": "MIT" + }, + "node_modules/solmate": { + "version": "6.6.2", + "resolved": "git+ssh://git@github.com/transmissions11/solmate.git#8d910d876f51c3b2585c9109409d601f600e68e1", + "integrity": "sha512-YwzT4J816jSPLNoWqg/zq1/Ghs0ePAAcJLOzS10CnvvGWg3GvvLNhMKTUJ8L+Q0zGzOIAaW/Lyx5IiE04MPk8A==", + "license": "AGPL-3.0-only" + }, + "node_modules/sshpk": { + "version": "1.18.0", + "dev": true, + "license": "MIT", + "dependencies": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sshpk/node_modules/tweetnacl": { + "version": "0.14.5", + "dev": true, + "license": "Unlicense" + }, + "node_modules/statuses": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/strict-uri-encode": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width": { + "version": "4.2.3", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-hex-prefix": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "is-hex-prefixed": "1.0.0" + }, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/swarm-js": { + "version": "0.1.42", + "dev": true, + "license": "MIT", + "dependencies": { + "bluebird": "^3.5.0", + "buffer": "^5.0.5", + "eth-lib": "^0.1.26", + "fs-extra": "^4.0.2", + "got": "^11.8.5", + "mime-types": "^2.1.16", + "mkdirp-promise": "^5.0.1", + "mock-fs": "^4.1.0", + "setimmediate": "^1.0.5", + "tar": "^4.0.2", + "xhr-request": "^1.0.1" + } + }, + "node_modules/swarm-js/node_modules/@sindresorhus/is": { + "version": "4.6.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/swarm-js/node_modules/@szmarczak/http-timer": { + "version": "4.0.6", + "dev": true, + "license": "MIT", + "dependencies": { + "defer-to-connect": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/swarm-js/node_modules/buffer": { + "version": "5.7.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/swarm-js/node_modules/cacheable-lookup": { + "version": "5.0.4", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.6.0" + } + }, + "node_modules/swarm-js/node_modules/cacheable-request": { + "version": "7.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^4.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^6.0.1", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/swarm-js/node_modules/fs-extra": { + "version": "4.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "node_modules/swarm-js/node_modules/get-stream": { + "version": "5.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/swarm-js/node_modules/got": { + "version": "11.8.6", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/is": "^4.0.0", + "@szmarczak/http-timer": "^4.0.5", + "@types/cacheable-request": "^6.0.1", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^5.0.3", + "cacheable-request": "^7.0.2", + "decompress-response": "^6.0.0", + "http2-wrapper": "^1.0.0-beta.5.2", + "lowercase-keys": "^2.0.0", + "p-cancelable": "^2.0.0", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=10.19.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/swarm-js/node_modules/http2-wrapper": { + "version": "1.0.3", + "dev": true, + "license": "MIT", + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.0.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, + "node_modules/swarm-js/node_modules/lowercase-keys": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/swarm-js/node_modules/normalize-url": { + "version": "6.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/swarm-js/node_modules/p-cancelable": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/swarm-js/node_modules/pump": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/swarm-js/node_modules/responselike": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "lowercase-keys": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/table": { + "version": "6.8.2", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/table/node_modules/ajv": { + "version": "8.16.0", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.4.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/table/node_modules/ansi-regex": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/table/node_modules/json-schema-traverse": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/table/node_modules/require-from-string": { + "version": "2.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/table/node_modules/strip-ansi": { + "version": "6.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar": { + "version": "4.4.19", + "dev": true, + "license": "ISC", + "dependencies": { + "chownr": "^1.1.4", + "fs-minipass": "^1.2.7", + "minipass": "^2.9.0", + "minizlib": "^1.3.3", + "mkdirp": "^0.5.5", + "safe-buffer": "^5.2.1", + "yallist": "^3.1.1" + }, + "engines": { + "node": ">=4.5" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "dev": true, + "license": "MIT" + }, + "node_modules/timed-out": { + "version": "4.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tough-cookie": { + "version": "2.5.0", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/tough-cookie/node_modules/punycode": { + "version": "2.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "dev": true, + "license": "MIT" + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/type": { + "version": "2.7.3", + "dev": true, + "license": "ISC" + }, + "node_modules/type-is": { + "version": "1.6.18", + "dev": true, + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "dev": true, + "license": "MIT", + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, + "node_modules/typescript": { + "version": "5.5.2", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/ultron": { + "version": "1.1.1", + "dev": true, + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "5.26.5", + "dev": true, + "license": "MIT" + }, + "node_modules/universalify": { + "version": "0.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url-set-query": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/utf-8-validate": { + "version": "5.0.10", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, + "node_modules/utf8": { + "version": "3.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/util": { + "version": "0.12.5", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/varint": { + "version": "5.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/vary": { + "version": "1.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/verror": { + "version": "1.10.0", + "dev": true, + "engines": [ + "node >=0.6.0" + ], + "license": "MIT", + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "node_modules/verror/node_modules/core-util-is": { + "version": "1.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/web3": { + "version": "1.10.4", + "dev": true, + "hasInstallScript": true, + "license": "LGPL-3.0", + "dependencies": { + "web3-bzz": "1.10.4", + "web3-core": "1.10.4", + "web3-eth": "1.10.4", + "web3-eth-personal": "1.10.4", + "web3-net": "1.10.4", + "web3-shh": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-bzz": { + "version": "1.10.4", + "dev": true, + "hasInstallScript": true, + "license": "LGPL-3.0", + "dependencies": { + "@types/node": "^12.12.6", + "got": "12.1.0", + "swarm-js": "^0.1.40" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-bzz/node_modules/@sindresorhus/is": { + "version": "4.6.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/web3-bzz/node_modules/@types/node": { + "version": "12.20.55", + "dev": true, + "license": "MIT" + }, + "node_modules/web3-bzz/node_modules/cacheable-lookup": { + "version": "6.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.6.0" + } + }, + "node_modules/web3-bzz/node_modules/cacheable-request": { + "version": "7.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^4.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^6.0.1", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/web3-bzz/node_modules/cacheable-request/node_modules/get-stream": { + "version": "5.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/web3-bzz/node_modules/cacheable-request/node_modules/lowercase-keys": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/web3-bzz/node_modules/form-data-encoder": { + "version": "1.7.1", + "dev": true, + "license": "MIT" + }, + "node_modules/web3-bzz/node_modules/got": { + "version": "12.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/is": "^4.6.0", + "@szmarczak/http-timer": "^5.0.1", + "@types/cacheable-request": "^6.0.2", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^6.0.4", + "cacheable-request": "^7.0.2", + "decompress-response": "^6.0.0", + "form-data-encoder": "1.7.1", + "get-stream": "^6.0.1", + "http2-wrapper": "^2.1.10", + "lowercase-keys": "^3.0.0", + "p-cancelable": "^3.0.0", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/web3-bzz/node_modules/normalize-url": { + "version": "6.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/web3-bzz/node_modules/pump": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/web3-bzz/node_modules/responselike": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "lowercase-keys": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/web3-bzz/node_modules/responselike/node_modules/lowercase-keys": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/web3-core": { + "version": "1.10.4", + "dev": true, + "license": "LGPL-3.0", + "dependencies": { + "@types/bn.js": "^5.1.1", + "@types/node": "^12.12.6", + "bignumber.js": "^9.0.0", + "web3-core-helpers": "1.10.4", + "web3-core-method": "1.10.4", + "web3-core-requestmanager": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-helpers": { + "version": "1.10.4", + "dev": true, + "license": "LGPL-3.0", + "dependencies": { + "web3-eth-iban": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-method": { + "version": "1.10.4", + "dev": true, + "license": "LGPL-3.0", + "dependencies": { + "@ethersproject/transactions": "^5.6.2", + "web3-core-helpers": "1.10.4", + "web3-core-promievent": "1.10.4", + "web3-core-subscriptions": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-promievent": { + "version": "1.10.4", + "dev": true, + "license": "LGPL-3.0", + "dependencies": { + "eventemitter3": "4.0.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-requestmanager": { + "version": "1.10.4", + "dev": true, + "license": "LGPL-3.0", + "dependencies": { + "util": "^0.12.5", + "web3-core-helpers": "1.10.4", + "web3-providers-http": "1.10.4", + "web3-providers-ipc": "1.10.4", + "web3-providers-ws": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core-subscriptions": { + "version": "1.10.4", + "dev": true, + "license": "LGPL-3.0", + "dependencies": { + "eventemitter3": "4.0.4", + "web3-core-helpers": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-core/node_modules/@types/node": { + "version": "12.20.55", + "dev": true, + "license": "MIT" + }, + "node_modules/web3-core/node_modules/bignumber.js": { + "version": "9.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/web3-eth": { + "version": "1.10.4", + "dev": true, + "license": "LGPL-3.0", + "dependencies": { + "web3-core": "1.10.4", + "web3-core-helpers": "1.10.4", + "web3-core-method": "1.10.4", + "web3-core-subscriptions": "1.10.4", + "web3-eth-abi": "1.10.4", + "web3-eth-accounts": "1.10.4", + "web3-eth-contract": "1.10.4", + "web3-eth-ens": "1.10.4", + "web3-eth-iban": "1.10.4", + "web3-eth-personal": "1.10.4", + "web3-net": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-abi": { + "version": "1.10.4", + "dev": true, + "license": "LGPL-3.0", + "dependencies": { + "@ethersproject/abi": "^5.6.3", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-accounts": { + "version": "1.10.4", + "dev": true, + "license": "LGPL-3.0", + "dependencies": { + "@ethereumjs/common": "2.6.5", + "@ethereumjs/tx": "3.5.2", + "@ethereumjs/util": "^8.1.0", + "eth-lib": "0.2.8", + "scrypt-js": "^3.0.1", + "uuid": "^9.0.0", + "web3-core": "1.10.4", + "web3-core-helpers": "1.10.4", + "web3-core-method": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-accounts/node_modules/bn.js": { + "version": "4.12.0", + "dev": true, + "license": "MIT" + }, + "node_modules/web3-eth-accounts/node_modules/eth-lib": { + "version": "0.2.8", + "dev": true, + "license": "MIT", + "dependencies": { + "bn.js": "^4.11.6", + "elliptic": "^6.4.0", + "xhr-request-promise": "^0.1.2" + } + }, + "node_modules/web3-eth-accounts/node_modules/uuid": { + "version": "9.0.1", + "dev": true, + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/web3-eth-contract": { + "version": "1.10.4", + "dev": true, + "license": "LGPL-3.0", + "dependencies": { + "@types/bn.js": "^5.1.1", + "web3-core": "1.10.4", + "web3-core-helpers": "1.10.4", + "web3-core-method": "1.10.4", + "web3-core-promievent": "1.10.4", + "web3-core-subscriptions": "1.10.4", + "web3-eth-abi": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-ens": { + "version": "1.10.4", + "dev": true, + "license": "LGPL-3.0", + "dependencies": { + "content-hash": "^2.5.2", + "eth-ens-namehash": "2.0.8", + "web3-core": "1.10.4", + "web3-core-helpers": "1.10.4", + "web3-core-promievent": "1.10.4", + "web3-eth-abi": "1.10.4", + "web3-eth-contract": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-iban": { + "version": "1.10.4", + "dev": true, + "license": "LGPL-3.0", + "dependencies": { + "bn.js": "^5.2.1", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-personal": { + "version": "1.10.4", + "dev": true, + "license": "LGPL-3.0", + "dependencies": { + "@types/node": "^12.12.6", + "web3-core": "1.10.4", + "web3-core-helpers": "1.10.4", + "web3-core-method": "1.10.4", + "web3-net": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-personal/node_modules/@types/node": { + "version": "12.20.55", + "dev": true, + "license": "MIT" + }, + "node_modules/web3-net": { + "version": "1.10.4", + "dev": true, + "license": "LGPL-3.0", + "dependencies": { + "web3-core": "1.10.4", + "web3-core-method": "1.10.4", + "web3-utils": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-providers-http": { + "version": "1.10.4", + "dev": true, + "license": "LGPL-3.0", + "dependencies": { + "abortcontroller-polyfill": "^1.7.5", + "cross-fetch": "^4.0.0", + "es6-promise": "^4.2.8", + "web3-core-helpers": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-providers-ipc": { + "version": "1.10.4", + "dev": true, + "license": "LGPL-3.0", + "dependencies": { + "oboe": "2.1.5", + "web3-core-helpers": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-providers-ws": { + "version": "1.10.4", + "dev": true, + "license": "LGPL-3.0", + "dependencies": { + "eventemitter3": "4.0.4", + "web3-core-helpers": "1.10.4", + "websocket": "^1.0.32" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-shh": { + "version": "1.10.4", + "dev": true, + "hasInstallScript": true, + "license": "LGPL-3.0", + "dependencies": { + "web3-core": "1.10.4", + "web3-core-method": "1.10.4", + "web3-core-subscriptions": "1.10.4", + "web3-net": "1.10.4" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-utils": { + "version": "1.10.4", + "dev": true, + "license": "LGPL-3.0", + "dependencies": { + "@ethereumjs/util": "^8.1.0", + "bn.js": "^5.2.1", + "ethereum-bloom-filters": "^1.0.6", + "ethereum-cryptography": "^2.1.2", + "ethjs-unit": "0.1.6", + "number-to-bn": "1.7.0", + "randombytes": "^2.1.0", + "utf8": "3.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-utils/node_modules/@noble/curves": { + "version": "1.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.4.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/web3-utils/node_modules/ethereum-cryptography": { + "version": "2.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@noble/curves": "1.4.0", + "@noble/hashes": "1.4.0", + "@scure/bip32": "1.4.0", + "@scure/bip39": "1.3.0" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/websocket": { + "version": "1.0.35", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bufferutil": "^4.0.1", + "debug": "^2.2.0", + "es5-ext": "^0.10.63", + "typedarray-to-buffer": "^3.1.5", + "utf-8-validate": "^5.0.2", + "yaeti": "^0.0.6" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/websocket/node_modules/debug": { + "version": "2.6.9", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/websocket/node_modules/ms": { + "version": "2.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.15", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "dev": true, + "license": "ISC" + }, + "node_modules/ws": { + "version": "8.17.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xhr": { + "version": "2.6.0", + "dev": true, + "license": "MIT", + "dependencies": { + "global": "~4.4.0", + "is-function": "^1.0.1", + "parse-headers": "^2.0.0", + "xtend": "^4.0.0" + } + }, + "node_modules/xhr-request": { + "version": "1.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-to-arraybuffer": "^0.0.5", + "object-assign": "^4.1.1", + "query-string": "^5.0.1", + "simple-get": "^2.7.0", + "timed-out": "^4.0.1", + "url-set-query": "^1.0.0", + "xhr": "^2.0.4" + } + }, + "node_modules/xhr-request-promise": { + "version": "0.1.3", + "dev": true, + "license": "MIT", + "dependencies": { + "xhr-request": "^1.1.0" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/yaeti": { + "version": "0.0.6", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.32" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "dev": true, + "license": "ISC" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 00000000..969050ab --- /dev/null +++ b/package.json @@ -0,0 +1,24 @@ +{ + "name": "zkOS", + "version": "1.0.0", + "description": "ZK contracts", + "author": "CardinalCryptography", + "license": "MIT", + "dependencies": { + "@openzeppelin/contracts": "=5.0.2", + "@openzeppelin/contracts-upgradeable": "=5.0.2", + "@uniswap/permit2": "github:Uniswap/permit2#cc56ad0f3439c502c246fc5cfcc3db92bb8b7219", + "solmate": "github:transmissions11/solmate#8d910d876f51c3b2585c9109409d601f600e68e1" + }, + "devDependencies": { + "@safe-global/protocol-kit": "^3.0.0", + "@safe-global/safe-core-sdk-types": "^4.0.0", + "child_process": "^1.0.2", + "dotenv": "^16.3.1", + "forge-std": "github:foundry-rs/forge-std#v1.8.1", + "prettier": "^3.2.5", + "prettier-plugin-solidity": "^1.3.1", + "solhint-community": "^3.7.0", + "solhint-plugin-prettier": "^0.1.0" + } +} diff --git a/poseidon2-solidity/generate_t8.py b/poseidon2-solidity/generate_t8.py new file mode 100644 index 00000000..695df069 --- /dev/null +++ b/poseidon2-solidity/generate_t8.py @@ -0,0 +1,591 @@ +from utils import * + +C = [0x09ac1c9e3e10275d303775ee5156cac5797286885ab6e9996cabd920c6d7301c, + 0x08f060c5232c1aa1af16c66c01f856ce21a23b904d785d93fc3eb1936ab1d138, + 0x16c305c00e00f6e363bb8a77d744aa2b635d2dbffc314489dcee7d40d2c46f41, + 0x1d26c1b8604f1fefd244c85950d363b0f00f76395549b57eee8974e94825001f, + 0x1ccfa9f0032a44338781dd65f6cbaf4f0221159ad6066a1d7118c7001f00a727, + 0x288e070870c152221cae14497e6d15f0477b166d87aa3fe424b27c16f24647f3, + 0x09799017ebafb853028ed86c952401f13a8ae699124b6ff91d465f95d15e682e, + 0x0e24363e8b1a38eb5f7ea8b4fb9be5d5a042286a1d101aa9b68f142b31cfcbba, + 0x23d15496aaf8d08c941e5f0e51f9c3da425f63fe7de65a757de241ff9dd858d4, + 0x0b59ce33289fde6d322091a8cf0274febf2a8c9947a6fe77df005eda0ce72358, + 0x246a6775827e13f8b5106f608d5ce6b6b0164b2930dd5f8a651319d495159c32, + 0x22c35a1c50346166066d9eac2cf28030fbeaffb92f6c4abf780db30314c455b5, + 0x09d4b0f893beb6c2299d8bf8d4abc4040cbee7e8200c615df858c1f12117e6fe, + 0x1b1cfc9db86ef3d2bc2fc8d3d4fc5af7cc309c56ff4da090f27b309462892c7d, + 0x1e5961cb7b443b1cede329a082a12391d085394cb15f059b337f2a68ec03238c, + 0x1a9bdaf4d98d73a9eda4e6d5e49e2b1f4f118e4e7747db22166adfb526cf7bdc, + 0x04b9b276e23c2b70abad7ff5979b53d43bf81bd62bc887cedf26514a56417764, + 0x0a7f9bcc69487481163ff3c9b9528601c7c585a99dedb947f4b06d4e11232e09, + 0x0892b44681eb2dbff423a072a414fe729eb8b6e0afbc4cce107d23420fb50b5a, + 0x22986810068c1126789654166390768aef29a4fa42099e70d4f88e1e397f33c3, + 0x1fd9742bb052485d8ec14535c8f547ac061594d868791e848ad63050d41e7e67, + 0x20afd72e943df193472287d025af8b15b7e1f33bc8dfb4e66ff418c21e29726d, + 0x29c8dfe8bd87048f764516a278b06202621232826c0d6f44ccc7b16d3f4db4d0, + 0x0c0d559596149f8ef8a2363173580a95dbb0a48d3df6692d8c464d5458d750a2, + 0x12d81fd7a038cecc3fb00c14f1aa69a37f466f88adcfde5399183fe8e4e1e891, + 0x2639eecb74b9039c5bafa3340977d4370324c06fbe8ac469f49954138d69418f, + 0x20803d5ef9dac956ff314289a051a1b188d83dc28eb0537b63d11ecccb598f60, + 0x2c06b7aa2e130ce462522972d69a14a49aabb0ab04dd1171bac0d98e76a51d57, + 0x0734c6c6d4ca8929a64277d878d22b708565255eb0f403d1405fe22f263df354, + 0x258434f4223a24498e4218185d147b9c8a86366eb9c2c8d0e83636415da25efd, + 0x20c664405dff550ee70c1018f904c1b730a40c809e05c2335f386d2f260b2271, + 0x1b2e3814ca161b5ea31300e1d93917de17bd3ae23d829f1d50a1fe45b1a3bf92, + 0x278bcde59972a426341454d7133f674b9757018decefd9ef427c15a1dfeba495, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x1289a9dea798f17a5ccdf7d6fbb874344a006f4fb8ba3cfca04aa825e5576f9b, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x193cc49c2a7b29ca0f2f48ee0b888573420fbad1f6940e33d222122ef9c19ff1, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x08f0817ee0880ca1a9c364cb822dc62bfb8e55e0600aba626fd60632032e3d26, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0743cca2f5f52aba55f00a836544be74bdcd58d00a469106a150209bdeabefa3, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0b40ae087bb22d27dbb604e1db3d7a4290344dcff3a14d36133f917de696fbaa, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x280c17f4eb155642545866c3e106116fab62d463ee09a23161d9fd21dd6ebece, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x25a9c20bb4c16c2d4b8420bee82f4ae13a33f3162c5dd671c072241068c002e6, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x077f1f9faffdd2b6f95abbaa8ad87d1381af6f6d33cc2a1ea59b017bc217d6b0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x234378508dcbc7dfc0703e93b0792d3515dbbe6e6e2eab128e80bfcf7b7c113b, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x1cf3aa5f02ee2df6d3f87d3ca5dd456fd1ae4dd59855886c3d1ff8a129a35317, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x2152736c3d4ccb7e44a53b81e7904987bf0a4313f72b61846fa9070c550bb05a, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0b1b1f58d94fcd20dc0e63473601849c3270b1ec9fea41262650eafe89c46dd3, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0df8cc60cf9f45ec72e8b8c30c52593b78696c11afcec5bdebc4f53b3c1930bc, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x2923b54561480b74a7933a0d20b13ce4e506fd697b01ee3e0deca8401a0246a6, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x2aa399823b60100f7c89f6fb73fed21fbf2f59971d284e623344b9300ff8a5db, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0561ce1ebf3b63833e454b8fcea1cc9c3a9ca9b743614421e9931f618a5e5726, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0925bb9e3066b445c08b8312d92fdcc1e51df0680ab66799e8b2a2b21d392957, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0c04706a3b94201828d0f0494a36474500550dc1201f8a2f62792cddbbd8f32b, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0128dde8a49eed960361fe3bd37c05b2b846d0b470e30ab2ea73c79b1ea8f323, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x03df347dcbd8e034286952884ce5c92ed0638681e20b634cd8d610e09b3bd9a8, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x1fca7c1836ff76d5413a1c442095f23fe173f2b81355b9e6d08c780a8419dd27, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x26be35036c894b8c5b7f76b7f145fc1b11b6edb6d36e5529ed6b0f177c8e5629, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x2de7b1981ddc04aac96f35f662c504ec108005cd939424eda85d942c5bccd6d8, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x1eb6f16a003ad510060db7c97327d746589f0806de290d3328c336ebc9b47b2f, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x02e489412625cfc78e81a80ebccf748bdb3530e2560cfd11c5883e153a4b7495, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x03acda95d5fb7131bfaaa47f14f31b952cd48105c60f18e488d4a144c314418e, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x2d326dafb456c100382599a32009d66699fe32f3c286ab85419068969dcca58e, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x12a1d012ae0f0f5d2b991a6fa6127383ff21e7657c0ba89a51e1bf013bcbcf6a, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x1833c5da8b3a3e1d6ce53a1c1c49878cc5bdcfec193a4a6885e582d2878bdf5d, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x18ab263b20a35eb4db42a2e37c84b7fe9aa6f32af02223e03a0faa3c21f7399c, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x20da99b866567c65abef92c5c53eaf0da86f2c4d9f77b48ebd465e77b1a2e3ea, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x2b7b9e823566cd468a1b05a6809e0aa1562991dee2575d047cec1e202f801fb5, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x2a6506e6758a51e2da28e7d2f9cb10e17ad2373d452f6b7eabc2a91b13b5e7f3, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x1b9f6c751d69078cea6274cb5f8d6da5a8ff26f4a127a5fd1855420df0b243a2, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x124d93ec00906df0029235dabb955e93ef29334d3006bc6e2e02bb2f25ba0e34, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x048813019294fad3449ca77fd59404ff2df976299b96ee33921e96eaab51e8ff, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x22a1d2d95c972af73f98bf9db89ba610dac6bd10e438d996028a424373411a25, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x029bf064ff8f123580d2341743905526043412990b6c2a060e503010f651beea, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x068ca3e7d66cff7b5fb3d4ace5689e4ac038db81fb237e4530b8d01c6019cab3, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x12b1511dfe65b516dde917f073f64c81b645383bbb7720342d0dd20888c77010, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x2e12974776ceed6cf82c61638595671595d62d5993ffdbc088222b484c6fa016, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x170f0ff28204619b05acfb5bd5a358b2216ab705725b38c3931a87ab0a1cfb6a, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x147fb5dc45a782811ea5cb869bedac4bb40499e2452783b351703e46bc41615b, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x02d2c5dd59168e8aff8f31beb7ba9883025ea4e213d25f7cdcb4ff82197bfbdd, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x26923d57346cb47f2d0235fca236fea36d0458d3ca92c21ea7dd3c9378ebc9e0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x283a2ae05ef6514d3c0824e37466c81fccc274c3a314e4b20292fc11d27961dd, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0fdcc959ede1ffb97b25ea49ea0a3d8a0d4079356b3ec111041b1a10e0700f32, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x0, + 0x1372a6901a4ec451f5b96b9fc628e326c0112e89d2c54185b3dfe5569d85318c, + 0x2512c8947f0079f2cb6cd5a0f619b95f24f856f4a1cf1f38c1c5bc0f9de24031, + 0x258b296d643fe88e3e786927741178c5f304221d8abdff3ba000a1ce743ed959, + 0x1d480d8170885f4e3731710f70ae26083135629a34a46f6917bd868a97a694c9, + 0x1c2ace4bdd9a812286bf27022dc093a6c3a9b3690f4c86465e6ce4f511f60a0e, + 0x0e0e6d53dd4248d145389a29da1970dd8a97519e42fabb399e684e5ca47cd675, + 0x2ecdf548f684b9cd6be8d2fa80a5f9568065ad78fdb5d0ec26bc6bec86a5e321, + 0x24895602e3e9f930baee72146f0c74e94c12fd9edc4730ecae075cb7deef1160, + 0x22908a9bf937a4abd33bee36b37a6ef13d6a6e1e45918f01d491ecf2b9b7102e, + 0x21a12f6ceb8b4f34de7d7a341667da38e0dd80966b26ffb76bf81a0fcf433ddf, + 0x19b7cede537d8a7d13a0a66d55bf6632a8574ded92a54a679349aaa03edde619, + 0x0baa9c79fdc85061922dedbe4cf32fb3c848f98c9438703ecbd8197884ada1e6, + 0x00f62c3ddeb876748d679f5e6a8bfabe70dee502d26ab578670293c44179e5be, + 0x1cb1f7ec2c74394b8b62115ccac06d81fc4de75f6200a6c862bec32a9d545438, + 0x0c326cd80ccd7efeef332da985857ec8431e72a34254a9e674dc9209eaa9c387, + 0x2d5d55cf84ed356ead441b27826a273e99593d00ca87e1f9b016550582ae4bea, + 0x15148cdd8b09b38f43c45ba811215f05b7395bd3b7da45ee81182a5639352f79, + 0x246d469cf15110e4e87b0560ba5dfbd49173a2c39f528fd4a09bb2b04b903575, + 0x04421c01d68b6daa5d8a924014e1a1282f8ffbc80aaff134ec95f936e5d38911, + 0x25c8130080eeaf48c6fb5ea35b270573f713e5abc1c134481e8ae51297bf4ee4, + 0x072034411f737d50601df3386b0b31445c817d7de3e3b6121ee45082a70c6734, + 0x0e2f84eb9c68559e895dc66cfed4e044f055b75eeef9c9b8b53e0fce7b6f2878, + 0x02f49f929c0b519583001275c9233c16e5a505059d506c2d7004fdb4c8c99865, + 0x07b6bf158a9a749d17660ef947a2752388d3092f98832c39440501507d72ca11, + 0x11dbdc3a4a54643a97bcfde065920e619d3ca193bbad2cd2204de91c19e47328, + 0x1b334393e11a3c268544ad1c564c63fb371d428fac91fb440e5b28840bd81b09, + 0x25717982e0fb2a83a013ebef07f8396a7309ff31a9f8d90f204081628f9fff51, + 0x2095152e0c43304da9c8e85dfa9096e3d340075ed8b223dec2a11e3d7bc4af84, + 0x0d9f3ccccb95ef72eee93f76ec5cef9c82379ce31e835b7e4698af7289be2bd0, + 0x0c1321ae313144a9705d1ccc5db5cf5fd6e33374cb62b477d7c3ff27a1bebc37, + 0x2bb501181adff644f38d7688e96f065c987ba451283620d3d64ee35b9e14862b, + 0x2205947785d825af9b0dbb3d9b503eafb63d1af46c171c3f598338b28888d89e] + +D = [2600766909924179814780409961696866414079699656430070499803459729017893381997, + 19293363242678774625215171492393209093707286181479006293654394057747218353607, + 21414786808156610356356451480905960406647514095406216853368573063004475600640, + 8215135898581116354906741804378477022438799156627805573019887031189487620936, + 9165814748476180913577766403125055556952884368727238651703828504915350029819, + 15078459252378813527385228808553999657222567675360137586804698725603240352055, + 5648186893216350474836221186116590993767413676065426352255299742021094533501, + 20725344080263893594397636575905698660034655258256134536883719628954264697683] +T = 8 +M = [[10, 14, 2, 6, 5, 7, 1, 3], + [8, 12, 2, 2, 4, 6, 1, 1], + [2, 6, 10, 14, 1, 3, 5, 7], + [2, 2, 8, 12, 1, 1, 4, 6], + [5, 7, 1, 3, 10, 14, 2, 6], + [4, 6, 1, 1, 8, 12, 2, 2], + [1, 3, 5, 7, 2, 6, 10, 14], + [1, 1, 4, 6, 2, 2, 8, 12]] + +ALPHA = 7 +ROUNDS_F = 8 +ROUNDS_P = 48 + +def define_functions(): + return f''' + + function sum() {{ + {store0(addmod(add(addmod(add(load0(), load1(), load2(), load3(), load4()), load5()), load6()), load7()), swap=True)} + }} + + function mm4(a, b, c, d) {{ + let t0 := {add('mload(a)', 'mload(b)')} // a + b + let t1 := {add('mload(c)', 'mload(d)')} // + c + d + let t2 := {add('mload(b)', 'mload(b)', 't1')} // + 2b + c + d + let t3 := {add('mload(d)', 'mload(d)', 't0')} // a + b + 2d + let t4 := {add('t1', 't1')} // 2c + 2d + t4 := {addmod('t4', 't4')} // 4c + 4d + t4 := {addmod('t4', 't3')} // a + b + 4c + 6d + let t5 := {add('t0', 't0')} // 2a + 2b + t5 := {addmod('t5', 't5')} // 4a + 4b + t5 := {addmod('t5', 't2')} // 4a + 6b + c + d + + mstore(a, {addmod('t3', 't5')}) + mstore(b, t5) + mstore(c, {addmod('t2', 't4')}) + mstore(d, t4) + }} + + function fr_mm() {{ + mm4({MEM[0]}, {MEM[1]}, {MEM[2]}, {MEM[3]}) + mm4({MEM[4]}, {MEM[5]}, {MEM[6]}, {MEM[7]}) + + {store0(add(load0(), load4()), swap=True)} + {store1(add(load1(), load5()), swap=True)} + {store2(add(load2(), load6()), swap=True)} + {store3(add(load3(), load7()), swap=True)} + + {store0(addmod(load0(), load0(swap=True)))} + {store1(addmod(load1(), load1(swap=True)))} + {store2(addmod(load2(), load2(swap=True)))} + {store3(addmod(load3(), load3(swap=True)))} + {store4(addmod(load4(), load0(swap=True)))} + {store5(addmod(load5(), load1(swap=True)))} + {store6(addmod(load6(), load2(swap=True)))} + {store7(addmod(load7(), load3(swap=True)))} + }} + + function fr_intro(c0, c1, c2, c3, c4, c5, c6, c7) {{ + let state0 := {add(load0(), 'c0')} + {pow_store(ALPHA, 'state0', MEM[0])} + + let state1 := {add(load1(), 'c1')} + {pow_store(ALPHA, 'state1', MEM[1])} + + let state2 := {add(load2(), 'c2')} + {pow_store(ALPHA, 'state2', MEM[2])} + + let state3 := {add(load3(), 'c3')} + {pow_store(ALPHA, 'state3', MEM[3])} + + let state4 := {add(load4(), 'c4')} + {pow_store(ALPHA, 'state4', MEM[4])} + + let state5 := {add(load5(), 'c5')} + {pow_store(ALPHA, 'state5', MEM[5])} + + let state6 := {add(load6(), 'c6')} + {pow_store(ALPHA, 'state6', MEM[6])} + + let state7 := {add(load7(), 'c7')} + {pow_store(ALPHA, 'state7', MEM[7])} + }} +''' + + +def init(): + return f''' + {define_functions()} + + {store0(f'mload({ARG[0]})')} + {store1(f'mload({ARG[1]})')} + {store2(f'mload({ARG[2]})')} + {store3(f'mload({ARG[3]})')} + {store4(f'mload({ARG[4]})')} + {store5(f'mload({ARG[5]})')} + {store6(f'mload({ARG[6]})')} + {store7('129127208515966861312')} + + fr_mm() +''' + + +def full_round(r): + return f''' +{{ + fr_intro({C[T * r]}, {C[T * r + 1]}, {C[T * r + 2]}, {C[T * r + 3]}, {C[T * r + 4]}, {C[T * r + 5]}, {C[T * r + 6]}, {C[T * r + 7]}) + fr_mm() +}} +''' + + +def partial_round(r): + return f''' +{{ + let state0 := {add(load0(), C[T * r])} + {pow_store(ALPHA, 'state0', MEM[0])} + + sum() + {store0(addmod(mulmod(D[0], load0()), load0(swap=True)))} + {store1(addmod(mulmod(D[1], load1()), load0(swap=True)))} + {store2(addmod(mulmod(D[2], load2()), load0(swap=True)))} + {store3(addmod(mulmod(D[3], load3()), load0(swap=True)))} + {store4(addmod(mulmod(D[4], load4()), load0(swap=True)))} + {store5(addmod(mulmod(D[5], load5()), load0(swap=True)))} + {store6(addmod(mulmod(D[6], load6()), load0(swap=True)))} + {store7(addmod(mulmod(D[7], load7()), load0(swap=True)))} +}} +''' + +if __name__ == '__main__': + print(generate_code(init, full_round, partial_round, T, ROUNDS_F, ROUNDS_P)) diff --git a/poseidon2-solidity/utils.py b/poseidon2-solidity/utils.py new file mode 100644 index 00000000..4621319b --- /dev/null +++ b/poseidon2-solidity/utils.py @@ -0,0 +1,143 @@ +# BN254/BN256 field modulus +F = 21888242871839275222246405745257275088548364400416034343698204186575808495617 + +# Memory slot addresses for the state +MEM = ['0x00', '0x20', '0x80', '0xa0', '0xc0', '0xe0', '0x100', '0x120'] +# Memory slot addresses for the swap variables +MEM_SWP = ['0x140', '0x160', '0x180', '0x1a0', '0x1c0', '0x1e0', '0x200', '0x220'] +# Memory slot addresses for the function arguments +ARG = ['0x080', '0x0a0', '0x0c0', '0x0e0', '0x100', '0x120', '0x140'] + + +def wrap_into_full_code(assembly_code, T): + """Wrap the assembly code into a full Solidity contract.""" + + return f""" +pragma solidity 0.8.26; +library Poseidon2T{T}Assembly {{ + function hash(uint256[{T - 1}] memory) public pure returns (uint256) {{ + assembly {{ + +{''.join(3 * chr(9) + a + chr(10) for a in assembly_code)} + + }} + }} +}}""" + + +def mulmod(a, b): + """Return the assembly code for the multiplication of two variables modulo `F`.""" + return f'mulmod({a}, {b}, {F})' + + +def add(*summands): + """Return the assembly code for the addition of multiple variables. + Useful when adding no more than `2**256 // F` variables (i.e. 5): saves some gas on modulo.""" + + if len(summands) == 1: + return summands[0] + return f'add({summands[0]}, {add(*summands[1:])})' + + +def addmod(a, b): + """Return the assembly code for the addition of two variables modulo `F`.""" + return f'addmod({a}, {b}, {F})' + + +def pow(alpha, var): + """Router function for `pow5` and `pow7`.""" + if alpha == 5: + return pow5(var) + elif alpha == 7: + return pow7(var) + + +def pow_store(alpha, var, at): + """Router function for `pow5_store` and `pow7_store`.""" + if alpha == 5: + return pow5_store(var, at) + elif alpha == 7: + return pow7_store(var, at) + + +def pow5(var): + """Return the assembly code for the exponentiation of a variable to the power of 5 modulo `F`.""" + + return f'''{{ + let aux_pow := {mulmod(var, var)} + {var} := {mulmod(mulmod('aux_pow', 'aux_pow'), var)} +}}''' + + +def pow5_store(var, at): + """Return the assembly code for the exponentiation of a variable to the power of 5 modulo `F` and store the + result in memory.""" + + return f'''{{ + let aux_pow := {mulmod(var, var)} + mstore({at}, {mulmod(mulmod('aux_pow', 'aux_pow'), var)}) +}}''' + + +def pow7(var): + """Return the assembly code for the exponentiation of a variable to the power of 7 modulo `F`.""" + + return f'''{{ + let var2 := {mulmod(var, var)} + let var4 := {mulmod('var2', 'var2')} + {var} := {mulmod(mulmod('var4', 'var2'), var)} +}}''' + + +def pow7_store(var, at): + """Return the assembly code for the exponentiation of a variable to the power of 7 modulo `F` and store the + result in memory.""" + + return f'''{{ + let var2 := {mulmod(var, var)} + let var4 := {mulmod('var2', 'var2')} + mstore({at}, {mulmod(mulmod('var4', 'var2'), var)}) +}}''' + + +# Memory load and store functions +def load0(swap=False): return f'mload({MEM_SWP[0] if swap else MEM[0]})' +def load1(swap=False): return f'mload({MEM_SWP[1] if swap else MEM[1]})' +def load2(swap=False): return f'mload({MEM_SWP[2] if swap else MEM[2]})' +def load3(swap=False): return f'mload({MEM_SWP[3] if swap else MEM[3]})' +def load4(swap=False): return f'mload({MEM_SWP[4] if swap else MEM[4]})' +def load5(swap=False): return f'mload({MEM_SWP[5] if swap else MEM[5]})' +def load6(swap=False): return f'mload({MEM_SWP[6] if swap else MEM[6]})' +def load7(swap=False): return f'mload({MEM_SWP[7] if swap else MEM[7]})' + + +def store0(val, swap=False): return f'mstore({MEM_SWP[0] if swap else MEM[0]}, {val})' +def store1(val, swap=False): return f'mstore({MEM_SWP[1] if swap else MEM[1]}, {val})' +def store2(val, swap=False): return f'mstore({MEM_SWP[2] if swap else MEM[2]}, {val})' +def store3(val, swap=False): return f'mstore({MEM_SWP[3] if swap else MEM[3]}, {val})' +def store4(val, swap=False): return f'mstore({MEM_SWP[4] if swap else MEM[4]}, {val})' +def store5(val, swap=False): return f'mstore({MEM_SWP[5] if swap else MEM[5]}, {val})' +def store6(val, swap=False): return f'mstore({MEM_SWP[6] if swap else MEM[6]}, {val})' +def store7(val, swap=False): return f'mstore({MEM_SWP[7] if swap else MEM[7]}, {val})' + + +def generate_code(init, full_round, partial_round, t, full_rounds, partial_rounds): + """Generate the full assembly code for the Poseidon hash function with given parameters and function generators.""" + + code = init() + + partial_rounds_begin = full_rounds // 2 + partial_rounds_end = partial_rounds_begin + partial_rounds + final_full_rounds_end = full_rounds + partial_rounds + + for r in range(partial_rounds_begin): + code += full_round(r) + for r in range(partial_rounds_begin, partial_rounds_end): + code += partial_round(r) + for r in range(partial_rounds_end, final_full_rounds_end): + code += full_round(r) + + # We assume that the result is stored in the first memory slot. + code += f'return({MEM[0]}, 0x20)' + + return wrap_into_full_code(code.split('\n'), t) diff --git a/resources/ppot_0080_11.ptau b/resources/ppot_0080_11.ptau new file mode 100644 index 00000000..96ccdeaf Binary files /dev/null and b/resources/ppot_0080_11.ptau differ diff --git a/resources/ppot_0080_11_raw b/resources/ppot_0080_11_raw new file mode 100644 index 00000000..fb5b8c4a Binary files /dev/null and b/resources/ppot_0080_11_raw differ diff --git a/resources/ppot_0080_13.ptau b/resources/ppot_0080_13.ptau new file mode 100644 index 00000000..fb211581 Binary files /dev/null and b/resources/ppot_0080_13.ptau differ diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 00000000..56e4f3b8 --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,4 @@ +[toolchain] +channel = "nightly-2024-07-08" +components = [ "rustfmt", "clippy", "rust-src" ] +targets = [ "x86_64-unknown-linux-gnu" ] diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 00000000..af85000b --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,7 @@ +edition = "2021" +use_field_init_shorthand = true +reorder_modules = true + +imports_granularity = "Crate" +group_imports = "StdExternalCrate" +reorder_imports = true diff --git a/scripts/Shielder.s.sol b/scripts/Shielder.s.sol new file mode 100644 index 00000000..848979c9 --- /dev/null +++ b/scripts/Shielder.s.sol @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.14; + +import { Script, console2 } from "forge-std/src/Script.sol"; + +import { ERC1967Proxy } from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; +import { Halo2Verifier as NewAccountVerifier } from "../contracts/NewAccountVerifier.sol"; +import { Halo2VerifyingKey as NewAccountVerifyingKey } from "../contracts/NewAccountVerifyingKey.sol"; +import { Halo2Verifier as DepositVerifier } from "../contracts/DepositVerifier.sol"; +import { Halo2VerifyingKey as DepositVerifyingKey } from "../contracts/DepositVerifyingKey.sol"; +import { Halo2Verifier as WithdrawVerifier } from "../contracts/WithdrawVerifier.sol"; +import { Halo2VerifyingKey as WithdrawVerifyingKey } from "../contracts/WithdrawVerifyingKey.sol"; +import { Shielder } from "../contracts/Shielder.sol"; + +/* solhint-disable no-console */ +contract DeployShielderScript is Script { + function run() external { + uint256 privateKey = vm.envUint("PRIVATE_KEY"); + + address owner = vm.addr(privateKey); + console2.log("Using", owner, "as broadcaster"); + + vm.startBroadcast(privateKey); + + NewAccountVerifier newAccountVerifier = new NewAccountVerifier(); + console2.log( + "NewAccountVerifier deployed at:", + address(newAccountVerifier) + ); + NewAccountVerifyingKey newAccountVerifyingKey = new NewAccountVerifyingKey(); + console2.log( + "NewAccountVerifyingKey deployed at:", + address(newAccountVerifyingKey) + ); + + DepositVerifier depositVerifier = new DepositVerifier(); + console2.log("DepositVerifier deployed at:", address(depositVerifier)); + DepositVerifyingKey depositVerifyingKey = new DepositVerifyingKey(); + console2.log( + "DepositVerifyingKey deployed at:", + address(depositVerifyingKey) + ); + + WithdrawVerifier withdrawVerifier = new WithdrawVerifier(); + console2.log( + "WithdrawVerifier deployed at:", + address(withdrawVerifier) + ); + WithdrawVerifyingKey withdrawVerifyingKey = new WithdrawVerifyingKey(); + console2.log( + "WithdrawVerifyingKey deployed at:", + address(withdrawVerifyingKey) + ); + + address shielderImplementation = address(new Shielder()); + + bytes memory data = abi.encodeCall( + Shielder.initialize, + ( + owner, + address(newAccountVerifier), + address(depositVerifier), + address(withdrawVerifier), + address(newAccountVerifyingKey), + address(depositVerifyingKey), + address(withdrawVerifyingKey), + type(uint256).max + ) + ); + + address proxy = address(new ERC1967Proxy(shielderImplementation, data)); + + Shielder shielder = Shielder(proxy); + + console2.log("Shielder deployed at:", address(shielder)); + shielder.unpause(); + + vm.stopBroadcast(); + } +} diff --git a/scripts/aleph-anvil.sh b/scripts/aleph-anvil.sh new file mode 100755 index 00000000..740805a4 --- /dev/null +++ b/scripts/aleph-anvil.sh @@ -0,0 +1,90 @@ +#!/usr/bin/env bash + +# This script is used to start the Anvil service configured to be as close as possible to the production environment. +# +# This script also accepts env variables instead of arguments. All arguments are optional. +# +# You need to have installed following prerequisites in order to use that script: +# * jq +# * foundry suite (forge, anvil) + +set -euo pipefail + +function error() { + echo [ERROR] $* + exit 1 +} + +# ============================ Argument parsing and usage ============================================================== + +PORT=${PORT:-8545} +CODE_SIZE_LIMIT=${CODE_SIZE_LIMIT:-96000} + +function usage(){ + cat << EOF +Usage: + $0 + [-p|--port PORT] + Port to run the Anvil service on. Default is 8545. Can also be set with the PORT env variable. + [--code-size-limit CODE_SIZE_LIMIT] + Maximum code size limit for the Anvil service. Default is 96kb. Can also be set with the CODE_SIZE_LIMIT env variable. +EOF + exit 0 +} + +while [[ $# -gt 0 ]]; do + case "$1" in + -p|--port) + PORT="$2" + shift;shift + ;; + --code-size-limit) + CODE_SIZE_LIMIT="$2" + shift;shift + ;; + *) + error "Unrecognized argument $1!" + ;; + esac +done + +if ss -tuln | grep -q ":${PORT} "; then + error "Port ${PORT} is occupied." +fi + +# ============================ Check required tools ==================================================================== + +for cmd in jq forge anvil; do + if ! command -v "$cmd" &> /dev/null; then + error "$cmd could not be found on PATH!" + fi +done + +# ============================ Current directory ======================================================================= + +script_path="${BASH_SOURCE[0]}" +script_dir=$(dirname "${script_path}") +root_dir=$(realpath "${script_dir}/..") +pushd "${root_dir}" > /dev/null + +# ============================ Prepare Arbitrum precompiles ============================================================ + +forge build contracts/ArbSysMock.sol > /dev/null +ARB_SYS_BYTECODE=$(jq '.deployedBytecode.object' artifacts/ArbSysMock.sol/ArbSysMock.json) +echo "Arbitrum precompiles prepared" + +# ============================ Start Anvil service ===================================================================== + +anvil --port "${PORT}" --code-size-limit "${CODE_SIZE_LIMIT}" > /dev/null & +sleep 0.5 # Wait for Anvil to start +echo "Anvil service started on port ${PORT}" + +# ============================ Deploy Arbitrum precompiles ============================================================= + +cast rpc --rpc-url "127.0.0.1:${PORT}" anvil_setCode 0x0000000000000000000000000000000000000064 ${ARB_SYS_BYTECODE} \ + > /dev/null +echo "Precompiles deployed" + +# ============================ Cleanup ================================================================================= + +popd > /dev/null diff --git a/scripts/install-sccache b/scripts/install-sccache new file mode 100755 index 00000000..ad5c4963 --- /dev/null +++ b/scripts/install-sccache @@ -0,0 +1,87 @@ +#!/usr/bin/env bash + +SCCACHE_VERSION="${SCCACHE_VERSION:-0.5.4}" +SCCACHE_INSTALL_DIR="${SCCACHE_INSTALL_DIR:-$HOME/.cargo/bin}" + +function .log() { + echo "[sccache::installer]" "$@" >&2 +} + +function .get_platform_triple() { + # e.g. "linux" + local os + os="$(uname | tr '[:upper:]' '[:lower:]')" + + # e.g. "x86_64" + local platform + platform="$(uname -p)" + + if [[ "$os" == "linux" ]]; then + echo "${platform}-unknown-${os}-musl" + else + .log "ERROR: Unsupported operating system ${os}" + return 1 + fi +} + +function .get_download_url() { + local triple + triple="$(.get_platform_triple)" + + local version + version="${SCCACHE_VERSION}" + + echo "https://github.com/mozilla/sccache/releases/download/v${version}/sccache-v${version}-${triple}.tar.gz" +} + +function .install_sccache() { + local triple + triple="$(.get_platform_triple)" + + local version + version="${SCCACHE_VERSION}" + + local url + url="$(.get_download_url)" + + local tmpdir + tmpdir="$(mktemp -d)" + + local exec_file + exec_file="sccache-v${version}-${triple}/sccache" + + .log "Installing sccache ${version}..." + + ( + cd "${tmpdir}" && \ + curl -fsSL "${url}" | tar xzf - --strip-components=1 "${exec_file}" && \ + install -m 0755 sccache "${SCCACHE_INSTALL_DIR}/sccache" + ) + + if [ -d "${tmpdir}" ]; then + rm -r "${tmpdir}" + fi +} + +function .main() { + local installed_version + + if ! which sccache &>/dev/null ; then + .log "sccache not found on PATH, installing requested version" + .install_sccache + else + installed_version="$(sccache --version | awk '{print $2;}')" + + if [[ "${installed_version}" != "${SCCACHE_VERSION}" ]]; then + .log "Currently installed version (${installed_version} does not match requested version ${SCCACHE_VERSION}, reinstalling sccache" + .install_sccache + else + .log "Installed version is up to date with requested version, nothing to do" + fi + fi +} + +if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then + set -euo pipefail + .main "$@" +fi diff --git a/tooling-dev/Makefile b/tooling-dev/Makefile new file mode 100644 index 00000000..968a66bf --- /dev/null +++ b/tooling-dev/Makefile @@ -0,0 +1,49 @@ +GIT_SHA1_SHORT := $(shell cat .git-sha | tr -d '[:space:]') + +NETWORK ?= anvil +PRIVATE_KEY ?= 0xb6b15c8cb491557369f3c7d2c287b053eb229daa9c22138887752191c9520659 # pkey of the dev account `0x3f1Eae7D46d88F08fc2F8ed27FCb2AB183EB2d0E` prefunded with ETH on all networks +RELAYER_DOCKER_IMAGE ?= 573243519133.dkr.ecr.us-east-1.amazonaws.com/shielder-relayer:${GIT_SHA1_SHORT} + +.PHONY: help +help: # Show help for each of the Makefile recipes. + @grep -E '^[a-zA-Z0-9 -]+:.*#' Makefile | sort | while read -r l; do printf "\033[1;32m$$(echo $$l | cut -f 1 -d':')\033[00m:$$(echo $$l | cut -f 2- -d'#')\n"; done + +.PHONY: deps +deps: # Install dependencies +deps: + npm install + +.PHONY: anvil +anvil: # Run local anvil node +anvil: + ./scripts/aleph-anvil.sh -p 8545 + +.PHONY: stop-anvil +stop-anvil: # Stop local anvil node +stop-anvil: + pkill anvil + +.PHONY: deploy-contracts +deploy-contracts: # Deploy solidity contracts +deploy-contracts: deps +ifeq ($(NETWORK),anvil) + PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 forge script DeployShielderScript --broadcast --rpc-url anvil +else + PRIVATE_KEY=$(PRIVATE_KEY) forge script DeployShielderScript --broadcast --rpc-url $(NETWORK) +endif + +.PHONY: download-relayer +download-relayer: # Download relayer docker image +download-relayer: + docker pull ${RELAYER_DOCKER_IMAGE} + +.PHONY: run-relayer +run-relayer: # Run relayer +run-relayer: download-relayer + source ./local_env.sh && \ + SHIELDER_CONTRACT_ADDRESS="0x8A791620dd6260079BF849Dc5567aDC3F2FdC318" \ + NODE_RPC_URL="http://host.docker.internal:8545" \ + DOCKER_USER="$(id -u):$(id -g)" \ + RELAYER_CONTAINER_NAME=shielder-relayer \ + RELAYER_DOCKER_IMAGE=${RELAYER_DOCKER_IMAGE} \ + ./run-relayer.sh diff --git a/tooling-dev/README.md b/tooling-dev/README.md new file mode 100644 index 00000000..34224df4 --- /dev/null +++ b/tooling-dev/README.md @@ -0,0 +1,31 @@ +# Shielder development environment + +## Prerequisites + +1. Make sure to have `foundry` installed [link](https://book.getfoundry.sh/getting-started/installation) +2. Make sure to have `npm` installed +3. Make sure to have `docker` installed +4. Have `AWS CLI` set up to aleph-zero mainnet AWS account, refer to https://www.notion.so/cardinalcryptography/Navigation-and-working-environment-05933ec1797f41139f7b28f8a0378210. Add docker registry as `aws ecr get-login-password --region us-east-1 --profile mainnet | docker login --username AWS --password-stdin 573243519133.dkr.ecr.us-east-1.amazonaws.com`. If you have troubles, contact our DevOps team. + +## How to set up environment + +1. Make sure to open the `tooling-dev` directory with the `Makefile`. +2. Run `make anvil` to run local Development node. +3. Run `make deploy-contracts` to deploy Shielder contract. +4. Run `make run-relayer`. + +## Miscellaneous + +- Node's default RPC URL is `http://localhost:8545` +- Contract default deployment address is `0x8A791620dd6260079BF849Dc5567aDC3F2FdC318` +- Relayer's default URL is `http://localhost:4141` +- In order to faucet tokens to address in devnet node, call [`anvil_setBalance`](https://book.getfoundry.sh/reference/anvil/#custom-methods) with `cast` tool (you should have it if you properly installed `foundry`): + +``` +cast rpc --rpc-url anvil anvil_setBalance 0xE7616f8F030A611be722A7787Ce183FD78B941C9 123 +``` + +- When something is not working, restart the env: + - `make stop-anvil` + - stop the docker container of relayer + - re-run setup steps diff --git a/tooling-e2e-tests/full_scenario.sh b/tooling-e2e-tests/full_scenario.sh new file mode 100755 index 00000000..a0d1926d --- /dev/null +++ b/tooling-e2e-tests/full_scenario.sh @@ -0,0 +1,57 @@ +#!/usr/bin/env bash + +set -euo pipefail + +SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd) +ROOT_DIR="${SCRIPT_DIR}/.." + +if [[ -n "${TESTNET:-}" ]]; then + source "${SCRIPT_DIR}/testnet_env.sh" +else + source "${SCRIPT_DIR}/local_env.sh" +fi +source "${SCRIPT_DIR}/utils.sh" + +scenario() { + configure_cli alice ${ALICE_PRIVATE_KEY} + + log_progress "✅ CLI configured" + alice app-config + + alice new-account $(mtzero 200) + alice deposit $(mtzero 100) + + log_progress "✅ Some deposits made" + alice display-account + alice history + + withdrawal_amount=$(mtzero 50) + + withdrawal_balance_before=$(cast balance -r "${NODE_RPC_URL}" "${WITHDRAWAL_PUBLIC_KEY}") + alice withdraw $withdrawal_amount "${WITHDRAWAL_PUBLIC_KEY}" + withdrawal_balance_after=$(cast balance -r "${NODE_RPC_URL}" "${WITHDRAWAL_PUBLIC_KEY}") + + withdrawn=$((withdrawal_balance_after - withdrawal_balance_before)) + if [ $withdrawn -ne $withdrawal_amount ]; then + log_progress "❌ Withdrawal failed: expected 5 mTZERO increase, got ${withdrawal_amount}" + exit 1 + else + log_progress "✅ Withdrawal successful" + fi + + alice display-account + alice history +} + +run() { + pushd $SCRIPT_DIR/.. &>> output.log + + setup + scenario + + popd &>> output.log +} + +trap cleanup EXIT SIGINT SIGTERM +rm -rf output.log +run diff --git a/tooling-e2e-tests/local_env.sh b/tooling-e2e-tests/local_env.sh new file mode 100644 index 00000000..eec543c0 --- /dev/null +++ b/tooling-e2e-tests/local_env.sh @@ -0,0 +1,67 @@ +# ====================================================================================================================== +# Node configuration +# ====================================================================================================================== +NODE_RPC_PORT=8545 +export NODE_RPC_PORT +NODE_RPC_URL="http://localhost:${NODE_RPC_PORT}" +export NODE_RPC_URL + +# ====================================================================================================================== +# Contract configuration +# ====================================================================================================================== +DEPLOYER_PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 # Pre-funded anvil account +export DEPLOYER_PRIVATE_KEY + +# ====================================================================================================================== +# User configuration +# ====================================================================================================================== +ALICE_PUBLIC_KEY=0xCaCa0634D1CEF7BD98c07e65C14Dd1B619906dD4 # Random address without any funds by default +export ALICE_PUBLIC_KEY +ALICE_PRIVATE_KEY=0xd5a92218e15fd2854d458af1a50c902e6ababaa34c3dfea239a5ef5eba651250 # Corresponding private key +export ALICE_PRIVATE_KEY + +BOB_PUBLIC_KEY=0xCAcA0eBb138B57A84EAF49B38dA122e507CE9a2f # Random address without any funds by default +export BOB_PUBLIC_KEY +BOB_PRIVATE_KEY=0x708e5a9d43a2a5b8eb4ccdd44ee7faebb559b5454a58f719dbb0ff904d047648 # Corresponding private key +export BOB_PRIVATE_KEY + +CHARLIE_PUBLIC_KEY=0xcACA0B734B779c97fc25BF9723e622649cFCDDfe # Random address without any funds by default +export CHARLIE_PUBLIC_KEY +CHARLIE_PRIVATE_KEY=0xa68e4f75a36d07db56c06b1103c9158801f0f1f24a07deae9324ee86b0753494 # Corresponding private key +export CHARLIE_PRIVATE_KEY + +WITHDRAWAL_PUBLIC_KEY=0xCaCA0cf7Ad10377313e391E8eF365c0ED0C51057 # Random address without any funds by default +export WITHDRAWAL_PUBLIC_KEY + +ALICE_STATE_FILE=~/.shielder-state-alice +BOB_STATE_FILE=~/.shielder-state-bob +CHARLIE_STATE_FILE=~/.shielder-state-charlie + +# ====================================================================================================================== +# Relayer configuration +# ====================================================================================================================== +RELAYER_PORT=4141 # Relayer service port +export RELAYER_PORT + +FEE_DESTINATION=0xcaca0a3147bcaf6d7B706Fc5F5c325E6b0e7fb34 # Random address without any funds by default. +export FEE_DESTINATION +FEE_DESTINATION_KEY=0x11bc58beea7f9baab53bbef30a478ebc1657b475869b0d966e8c17a02218e529 # Corresponding signing key. +export FEE_DESTINATION_KEY + +RELAYER_SIGNING_KEYS=0x547a81fc1782a6f29613dd15fe0f97321379875fe5a99e2a9d8258b4d51ac660,b466c488864884d64daf2ff0a117d4a39c10e6b294cb9199ff70730dcd84dcc0,ba07224f2bf545f5409be9fb09fd55d95ef9f8a2567461146b94a9a9e09ec1e2 +export RELAYER_SIGNING_KEYS +RELAYER_SIGNER_ADDRESSES=("0xCacA011152e011634cFC7f663998af44BC55FF4c" "0xCaCa0Bd0baFbea855b0Bb2776F689b0f46cFA592" "0xCAcA018473E24A5d1B993C26e88943C49b63ED98") +export RELAYER_SIGNER_ADDRESSES + +RELAYER_URL="http://localhost:${RELAYER_PORT}" +export RELAYER_URL + +NONCE_POLICY=caching +export NONCE_POLICY +DRY_RUNNING=optimistic +export DRY_RUNNING + +RELAY_COUNT_FOR_RECHARGE=1 +export RELAY_COUNT_FOR_RECHARGE +BALANCE_MONITOR_INTERVAL_SECS=5 +export BALANCE_MONITOR_INTERVAL_SECS diff --git a/tooling-e2e-tests/many_actors.sh b/tooling-e2e-tests/many_actors.sh new file mode 100755 index 00000000..b74d20ca --- /dev/null +++ b/tooling-e2e-tests/many_actors.sh @@ -0,0 +1,91 @@ +#!/usr/bin/env bash + +set -euo pipefail + +SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd) +ROOT_DIR="${SCRIPT_DIR}/.." + +if [[ -n "${TESTNET:-}" ]]; then + source "${SCRIPT_DIR}/testnet_env.sh" +else + source "${SCRIPT_DIR}/local_env.sh" +fi +source "${SCRIPT_DIR}/utils.sh" + +check_balances() { + alice_account=$(alice display-account) + if ! echo "${alice_account}" | grep -q "shielded_amount: 8000000000000000,"; then # 210 deposited, 2 withdrawn, 200 in fees + echo "❌ Alice has wrong shielded amount" + exit 1 + fi + + bob_account=$(bob display-account) + if ! echo "${bob_account}" | grep -q "shielded_amount: 216000000000000000,"; then # 420 deposited, 4 withdrawn, 200 in fees + echo "❌ Bob has wrong shielded amount" + exit 1 + fi + + charlie_account=$(charlie display-account) + if ! echo "${charlie_account}" | grep -q "shielded_amount: 424000000000000000,"; then # 630 deposited, 6 withdrawn, 200 in fees + echo "❌ Charlie has wrong shielded amount" + exit 1 + fi + + log_progress "✅ Accounts have the expected balances" +} + +scenario() { + configure_cli alice ${ALICE_PRIVATE_KEY} + configure_cli bob ${BOB_PRIVATE_KEY} + configure_cli charlie ${CHARLIE_PRIVATE_KEY} + + withdrawal_balance_before=$(cast balance -r "${NODE_RPC_URL}" "${WITHDRAWAL_PUBLIC_KEY}") + + alice new-account $(mtzero 100) + bob new-account $(mtzero 200) + + alice deposit $(mtzero 100) + bob deposit $(mtzero 200) + alice deposit $(mtzero 10) + bob deposit $(mtzero 20) + + alice withdraw $(mtzero 1) "${WITHDRAWAL_PUBLIC_KEY}" + bob withdraw $(mtzero 2) "${WITHDRAWAL_PUBLIC_KEY}" + alice withdraw $(mtzero 1) "${WITHDRAWAL_PUBLIC_KEY}" + bob withdraw $(mtzero 2) "${WITHDRAWAL_PUBLIC_KEY}" + + log_progress "✅ Some actions were made, alternating between Alice and Bob" + + charlie new-account $(mtzero 300) + charlie deposit $(mtzero 300) + charlie deposit $(mtzero 30) + charlie withdraw $(mtzero 3) "${WITHDRAWAL_PUBLIC_KEY}" + charlie withdraw $(mtzero 3) "${WITHDRAWAL_PUBLIC_KEY}" + + log_progress "✅ Charlie joined the party" + + withdrawal_balance_after=$(cast balance -r "${NODE_RPC_URL}" "${WITHDRAWAL_PUBLIC_KEY}") + withdrawal_amount=$(echo "$withdrawal_balance_after - $withdrawal_balance_before" | bc) + + if [[ $withdrawal_amount == $(mtzero 12) ]]; then + log_progress "✅ Withdrawals were successful - 444 mTZERO increase" + else + log_progress "❌ Some withdrawals failed: expected 444 mTZERO increase, got ${withdrawal_amount}" + exit 1 + fi + + check_balances +} + +run() { + pushd $SCRIPT_DIR/.. &>> output.log + + setup + scenario + + popd &>> output.log +} + +trap cleanup EXIT SIGINT SIGTERM +rm -rf output.log +run diff --git a/tooling-e2e-tests/recovery_scenario.sh b/tooling-e2e-tests/recovery_scenario.sh new file mode 100755 index 00000000..51d28c36 --- /dev/null +++ b/tooling-e2e-tests/recovery_scenario.sh @@ -0,0 +1,82 @@ +#!/usr/bin/env bash + +set -euo pipefail + +SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd) +ROOT_DIR="${SCRIPT_DIR}/.." + +if [[ -n "${TESTNET:-}" ]]; then + source "${SCRIPT_DIR}/testnet_env.sh" +else + source "${SCRIPT_DIR}/local_env.sh" +fi +source "${SCRIPT_DIR}/utils.sh" + +config_cli_for_recovery() { + alice initialize "${ALICE_PRIVATE_KEY}" + alice node-url "${NODE_RPC_URL}" + alice contract-address "${SHIELDER_CONTRACT_ADDRESS}" + + log_progress "✅ CLI minimally configured for recovery process" +} + +make_history() { + configure_cli alice ${ALICE_PRIVATE_KEY} + + alice new-account $(mtzero 500) # so that we have enough balance for withdrawals + alice deposit $(mtzero 6) + alice withdraw $(mtzero 7) "${WITHDRAWAL_PUBLIC_KEY}" + alice deposit $(mtzero 8) + alice withdraw $(mtzero 9) "${WITHDRAWAL_PUBLIC_KEY}" + + log_progress "✅ Some deposits and withdrawals made" +} + +# Scenario: +# 1. Start with clean state +# 2. Make some shielder operations +# 3. Lose the state +# 4. Recover the state +# 5. Check that the state is correct +scenario() { + make_history + + account_snapshot=$(alice display-account) + history_snapshot=$(alice history) + + clear_local_cli_state + log_progress "✅ State lost" + + config_cli_for_recovery + + alice recover-state + + account_now=$(alice display-account) + history_now=$(alice history) + + if [ "$account_snapshot" != "$account_now" ]; then + log_progress "❌ Account state mismatch" + exit 1 + fi + if [ "$history_snapshot" != "$history_now" ]; then + log_progress "❌ History state mismatch" + exit 1 + fi + + log_progress "✅ State recovered successfully" + alice display-account + alice history +} + +run() { + pushd $SCRIPT_DIR/.. &>> output.log + + setup + scenario + + popd &>> output.log +} + +trap cleanup EXIT SIGINT SIGTERM +rm -rf output.log +run diff --git a/tooling-e2e-tests/run-dev-relayer.sh b/tooling-e2e-tests/run-dev-relayer.sh new file mode 100755 index 00000000..edbbedd9 --- /dev/null +++ b/tooling-e2e-tests/run-dev-relayer.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +set -euo pipefail + +SCRIPT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd) +ROOT_DIR="${SCRIPT_DIR}/.." + +source "${SCRIPT_DIR}/env.sh" +source "${SCRIPT_DIR}/utils.sh" + +trap cleanup EXIT SIGINT SIGTERM + +setup + +docker logs shielder-relayer -f \ No newline at end of file diff --git a/tooling-e2e-tests/testnet_env.sh b/tooling-e2e-tests/testnet_env.sh new file mode 100644 index 00000000..3af72cd1 --- /dev/null +++ b/tooling-e2e-tests/testnet_env.sh @@ -0,0 +1,41 @@ +# Expected variables set from the outside: +# - DEPLOYER_PRIVATE_KEY +# - ALICE_PUBLIC_KEY +# - ALICE_PRIVATE_KEY +# - BOB_PUBLIC_KEY +# - BOB_PRIVATE_KEY +# - CHARLIE_PUBLIC_KEY +# - CHARLIE_PRIVATE_KEY +# - FEE_DESTINATION +# - FEE_DESTINATION_KEY +# - RELAYER_SIGNER_ADDRESSES - as array +# - RELAYER_SIGNING_KEYS - comma-separated + +NODE_RPC_URL="https://rpc.alephzero-testnet.gelato.digital" +export NODE_RPC_URL + +WITHDRAWAL_PUBLIC_KEY=0xCaCA0cf7Ad10377313e391E8eF365c0ED0C51057 # Random address +export WITHDRAWAL_PUBLIC_KEY + +ALICE_STATE_FILE=~/.shielder-state-alice +BOB_STATE_FILE=~/.shielder-state-bob +CHARLIE_STATE_FILE=~/.shielder-state-charlie + +# ====================================================================================================================== +# Relayer configuration +# ====================================================================================================================== +RELAYER_PORT=4141 # Relayer service port +export RELAYER_PORT + +RELAYER_URL="http://localhost:${RELAYER_PORT}" +export RELAYER_URL + +NONCE_POLICY=caching +export NONCE_POLICY +DRY_RUNNING=optimistic +export DRY_RUNNING + +RELAY_COUNT_FOR_RECHARGE=1 +export RELAY_COUNT_FOR_RECHARGE +BALANCE_MONITOR_INTERVAL_SECS=5 +export BALANCE_MONITOR_INTERVAL_SECS diff --git a/tooling-e2e-tests/utils.sh b/tooling-e2e-tests/utils.sh new file mode 100644 index 00000000..11af0d52 --- /dev/null +++ b/tooling-e2e-tests/utils.sh @@ -0,0 +1,162 @@ +#################################################################################################### +#### LOGGING ####################################################################################### +#################################################################################################### +get_timestamp() { + date +'%Y-%m-%d %H:%M:%S' +} + +log_progress() { + if [[ -z "${NO_FORMATTING:-}" ]]; then + bold=$(tput bold) + normal=$(tput sgr0) + echo "[$(get_timestamp)] ${bold}${1}${normal}" | tee -a output.log + else + echo "[$(get_timestamp)] ${1}" | tee -a output.logtsk + fi +} + +#################################################################################################### +#### NODE ########################################################################################## +#################################################################################################### +stop_node() { + anvil_pid=$(pgrep -f 'anvil' || true) + if [ -n "$anvil_pid" ]; then + kill "${anvil_pid}" + log_progress "✅ Stopped running anvil node" + fi +} + +start_node() { + stop_node + ./scripts/aleph-anvil.sh --port "${NODE_RPC_PORT}" &>> output.log + sleep 0.5 # Wait for the node to start, sometimes `curl` connects too fast. + + log_progress "✅ Anvil node started" +} + +#################################################################################################### +#### ACCOUNTS ###################################################################################### +#################################################################################################### +endow_accounts() { + AMOUNT=$(mtzero 100000) + + keys=("${ALICE_PUBLIC_KEY}" "${BOB_PUBLIC_KEY}" "${CHARLIE_PUBLIC_KEY}" "${RELAYER_SIGNER_ADDRESSES[@]}") + for key in "${keys[@]}"; do + curl "${NODE_RPC_URL}" -X POST -H "Content-Type: application/json" \ + --data '{"method":"anvil_setBalance","params":["'"${key}"'", "'${AMOUNT}'"],"id":1,"jsonrpc":"2.0"}' \ + &>> output.log + done + + log_progress "✅ Accounts endowed" +} + +mtzero() { + echo "${1}000000000000000" +} + +#################################################################################################### +#### CONTRACTS ##################################################################################### +#################################################################################################### +deploy_contracts() { + SHIELDER_CONTRACT_ADDRESS=$( + PRIVATE_KEY="${DEPLOYER_PRIVATE_KEY}" forge script DeployShielderScript \ + --rpc-url "${NODE_RPC_URL}" \ + --broadcast \ + --non-interactive \ + 2> /dev/null \ + | grep 'Shielder deployed at:' | awk '{print $NF}') + export SHIELDER_CONTRACT_ADDRESS + + log_progress "✅ Contracts deployed" +} + +#################################################################################################### +#### RELAYER ####################################################################################### +#################################################################################################### +start_relayer() { + cd "${ROOT_DIR}/crates/shielder-relayer/" + make run &>> output.log + cd "${ROOT_DIR}" + + log_progress "✅ Relayer started" +} + +stop_relayer() { + cd "${ROOT_DIR}/crates/shielder-relayer/" + make stop &>> output.log + cd "${ROOT_DIR}" + + log_progress "✅ Relayer stopped" +} + +#################################################################################################### +#### CLI ########################################################################################### +#################################################################################################### +build_cli() { + cargo build --release -p shielder-cli &>> output.log + + log_progress "✅ CLI built" +} + +alice() { + RUST_LOG=warning target/release/shielder-cli --no-password --state-file ${ALICE_STATE_FILE} "$@" +} + +bob() { + RUST_LOG=warning target/release/shielder-cli --no-password --state-file ${BOB_STATE_FILE} "$@" +} + +charlie() { + RUST_LOG=warning target/release/shielder-cli --no-password --state-file ${CHARLIE_STATE_FILE} "$@" +} + +clear_local_cli_state() { + rm -f ${ALICE_STATE_FILE} ${BOB_STATE_FILE} ${CHARLIE_STATE_FILE} + rm -rf ~/shielder-cli/ + + log_progress "✅ Local CLI states cleared (state files and proving keys)" +} + +configure_cli() { + ${1} initialize ${2} + ${1} node-url "${NODE_RPC_URL}" + ${1} contract-address "${SHIELDER_CONTRACT_ADDRESS}" + ${1} relayer-url "${RELAYER_URL}" + ${1} relayer-address "${FEE_DESTINATION}" + + log_progress "✅ CLI fully configured" +} + +#################################################################################################### +#### SETUP & CLEANUP ############################################################################### +#################################################################################################### +setup() { + if [[ ! -n "${TESTNET:-}" ]]; then + start_node + endow_accounts + fi + + build_cli + clear_local_cli_state + + deploy_contracts + start_relayer +} + +cleanup() { + if [[ "$?" -ne 0 ]]; then + echo -e "❌ Test failed. Printing output.log\n\n\n" + cat output.log + else + log_progress "✅ Test successfully passed" + log_progress "🗒 Script output saved to output.log" + fi + + docker logs shielder-relayer > relayer-output.log + log_progress "🗒 Relayer logs saved to relayer-output.log" + stop_relayer + + if [[ ! -n "${TESTNET:-}" ]]; then + stop_node + fi +} diff --git a/ts/browser-extension/.env b/ts/browser-extension/.env new file mode 100644 index 00000000..d700e8dd --- /dev/null +++ b/ts/browser-extension/.env @@ -0,0 +1,6 @@ +PLASMO_PUBLIC_PRIVATE_KEY= +PLASMO_PUBLIC_RPC_URL=https://rpc.alephzero-testnet.gelato.digital +PLASMO_PUBLIC_RELAYER_URL=https://shielder-relayer.test.azero.dev +PLASMO_PUBLIC_SHIELDER_CONTRACT_ADDRESS= +PLASMO_PUBLIC_CHAIN_ID=2039 +PLASMO_PUBLIC_RELAYER_ADDRESS=0xc8BED9372C5511De4bB39715801E6CfC6fa94c47 \ No newline at end of file diff --git a/ts/browser-extension/.eslintrc.cjs b/ts/browser-extension/.eslintrc.cjs new file mode 100644 index 00000000..29608df3 --- /dev/null +++ b/ts/browser-extension/.eslintrc.cjs @@ -0,0 +1,141 @@ +const commonImportsRestrictionPatterns = [{ + /* + Modules are often divided into sub-modules for readability and maintainability, where those + sub-modules are internal to the "root" modules. This rule prevents importing those sub-modules, + which happens often by laziness or an overlook, in order to keep the modules SOLID. + */ + group: ['@/*/*/**'], + message: 'Direct importing of sub-modules is not allowed. Turn the sub-module into a root module' + + ' or reexport it from the "owning" module if you really need to use it directly.', +}, { + /* + This rule promotes abstracting module's internal details away from the consumers. For instance, + a consumer should not care if a module is a simple, single-file module "src/module.ts" or + a complex directory with "src/module/index.ts" file: in both cases, the import should say: + "import from 'src/module'". + */ + group: ['**/index.*', '**/index', '!**/*.css'], + message: 'Take advantage of the fact that "index" files are implicit - import the directory instead.', +}]; + +module.exports = { + root: true, + env: { browser: true, es2020: true }, + extends: [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended", + "plugin:react-hooks/recommended", + "plugin:react/recommended", + "plugin:react/jsx-runtime", + "plugin:@tanstack/eslint-plugin-query/recommended" + ], + ignorePatterns: ["dist", ".eslintrc.cjs", 'vite.config.ts', 'tailwind.config.js', 'postcss.config.js', 'validate-envs.ts'], + parser: "@typescript-eslint/parser", + parserOptions: { + ecmaVersion: 'latest', + sourceType: 'module', + project: true, + tsconfigRootDir: __dirname, + }, + plugins: ['react-refresh', '@tanstack/query', 'import'], + settings: { + react: { + version: 'detect', + }, + }, + rules: { + quotes: ['error', 'single'], + 'comma-dangle': ['error', { + arrays: 'always-multiline', + objects: 'always-multiline', + imports: 'always-multiline', + exports: 'always-multiline', + functions: 'only-multiline', + }], + 'eol-last': ['error', 'always'], + 'import/order': ['error', { + pathGroups: [ + { + pattern: 'src/**', + group: 'internal', + }, + { + pattern: '.storybook/**', + group: 'internal', + }, + ], + distinctGroup: true, + pathGroupsExcludedImportTypes: ['builtin'], + groups: ['builtin', 'external', 'internal', 'parent', 'sibling'], + 'newlines-between': 'always', + alphabetize: { + order: 'asc', + }, + }], + '@typescript-eslint/object-curly-spacing': ['error', 'always', { + arraysInObjects: true, + objectsInObjects: false, + }], + 'operator-linebreak': ['error', 'after'], + 'react/jsx-indent': ['error', 2, { checkAttributes: true, indentLogicalExpressions: true }], + 'react/display-name': 'off', + 'react/react-in-jsx-scope': 'off', + 'quote-props': ['error', 'as-needed'], + indent: ['error', 2], + 'no-multiple-empty-lines': ['error', { max: 1, maxEOF: 0, maxBOF: 0 }], + 'no-multi-spaces': ['error'], + 'react/jsx-props-no-multi-spaces': 'error', + semi: ['error', 'always'], + 'react/jsx-max-props-per-line': ['error', { maximum: 1, when: 'multiline' }], + 'max-len': ['error', { code: 120, ignoreComments: true, ignoreUrls: true, ignoreStrings: true, ignoreTemplateLiterals: true, ignoreRegExpLiterals: true }], + 'object-shorthand': [2, 'always'], + 'no-restricted-imports': ['error', { + patterns: commonImportsRestrictionPatterns, + }], + 'no-trailing-spaces': 'error', + 'react-refresh/only-export-components': [ + 'warn', + { allowConstantExport: true } + ], + 'import/extensions': ['error', 'never', { 'json': 'always' }] + }, + overrides: [ + { + files: ['./**/*.{ts,tsx}'], + extends: [ + 'plugin:@typescript-eslint/strict-type-checked', + 'plugin:@typescript-eslint/stylistic-type-checked', + ], + parser: '@typescript-eslint/parser', + rules: { + '@typescript-eslint/member-delimiter-style': ['error', { + multiline: { delimiter: 'comma', requireLast: true }, + singleline: { delimiter: 'comma', requireLast: false }, + }], + '@typescript-eslint/no-confusing-void-expression': ['error', { ignoreVoidOperator: true }], + '@typescript-eslint/no-meaningless-void-operator': 'off', + '@typescript-eslint/consistent-type-definitions': ['error', 'type'], + '@typescript-eslint/semi': ['error', 'always'], + '@typescript-eslint/unbound-method': 'off', + indent: ['off'], + '@typescript-eslint/indent': ['error', 2, { + ignoredNodes: [ + 'TaggedTemplateExpression > TemplateLiteral *', + ], + }], + '@typescript-eslint/restrict-template-expressions': [ + 'error', + { + 'allowNumber': true + } + ], + }, + }, + { + files: ['.eslintrc.cjs'], + env: { + node: true, + }, + }, + ], +}; diff --git a/ts/browser-extension/.gitignore b/ts/browser-extension/.gitignore new file mode 100644 index 00000000..8171a7f6 --- /dev/null +++ b/ts/browser-extension/.gitignore @@ -0,0 +1,28 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +build +dist +dist-ssr +*.local +.plasmo +vite.config.*.timestamp-* + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? +.vercel diff --git a/ts/browser-extension/README.md b/ts/browser-extension/README.md new file mode 100644 index 00000000..611c21c1 --- /dev/null +++ b/ts/browser-extension/README.md @@ -0,0 +1,15 @@ +# Shielder Extension + +## Pre-installs + +`pnpm install` + +## Running extension + +`pnpm plasmo dev` + +Install in chrome. Build files are located at `build/chrome-mv3-dev` + +## Running web app + +`pnpm dev` diff --git a/ts/browser-extension/assets/icon.png b/ts/browser-extension/assets/icon.png new file mode 100644 index 00000000..8ff79757 Binary files /dev/null and b/ts/browser-extension/assets/icon.png differ diff --git a/ts/browser-extension/components.json b/ts/browser-extension/components.json new file mode 100644 index 00000000..1c6facd2 --- /dev/null +++ b/ts/browser-extension/components.json @@ -0,0 +1,17 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "default", + "rsc": false, + "tsx": true, + "tailwind": { + "config": "tailwind.config.js", + "css": "src/index.css", + "baseColor": "slate", + "cssVariables": true, + "prefix": "" + }, + "aliases": { + "components": "@/components", + "utils": "@/lib/utils" + } +} \ No newline at end of file diff --git a/ts/browser-extension/index.html b/ts/browser-extension/index.html new file mode 100644 index 00000000..96ebe144 --- /dev/null +++ b/ts/browser-extension/index.html @@ -0,0 +1,13 @@ + + + + + + + AZERO Wallet + + +
+ + + diff --git a/ts/browser-extension/package.json b/ts/browser-extension/package.json new file mode 100644 index 00000000..0ced7ad7 --- /dev/null +++ b/ts/browser-extension/package.json @@ -0,0 +1,76 @@ +{ + "name": "shielder-extension", + "private": true, + "version": "0.1", + "type": "module", + "scripts": { + "validate-envs": "tsx ./validate-envs.ts", + "dev": "export PLASMO_PUBLIC_STORAGE_MODE=webapp && vite", + "dev_ext": "export PLASMO_PUBLIC_STORAGE_MODE=extension && pnpm validate-envs && pnpm plasmo dev", + "build": "export PLASMO_PUBLIC_STORAGE_MODE=webapp && tsc -b && vite build", + "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", + "preview": "vite preview" + }, + "dependencies": { + "@hookform/resolvers": "^3.9.0", + "@radix-ui/react-dialog": "^1.1.1", + "@radix-ui/react-label": "^2.1.0", + "@radix-ui/react-slot": "^1.1.0", + "@radix-ui/react-switch": "^1.1.0", + "@radix-ui/react-toast": "^1.2.1", + "@radix-ui/react-tooltip": "^1.1.2", + "@tanstack/react-query": "^5.55.3", + "class-variance-authority": "^0.7.0", + "clsx": "^2.1.1", + "dotenv": "^16.4.5", + "eslint-plugin-import": "^2.30.0", + "eslint-plugin-react": "^7.35.2", + "lucide-react": "^0.407.0", + "plasmo": "^0.88.0", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-hook-form": "^7.52.2", + "shielder-sdk": "link:../shielder-sdk", + "tailwind-merge": "^2.4.0", + "tailwindcss-animate": "^1.0.7", + "viem": "^2.19.1", + "vite-plugin-env-compatible": "^2.0.1", + "zod": "^3.23.8" + }, + "devDependencies": { + "@tanstack/eslint-plugin-query": "^5.51.15", + "@types/chrome": "^0.0.268", + "@types/node": "^20.14.14", + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", + "@typescript-eslint/eslint-plugin": "^7.18.0", + "@typescript-eslint/parser": "^7.18.0", + "@vitejs/plugin-react": "^4.3.1", + "autoprefixer": "^10.4.20", + "eslint": "^8.57.0", + "eslint-plugin-react-hooks": "^4.6.2", + "eslint-plugin-react-refresh": "^0.4.9", + "postcss": "^8.4.41", + "tailwindcss": "^3.4.7", + "tsconfig-paths": "^4.2.0", + "tsx": "^4.19.0", + "typescript": "^5.5.4", + "vite": "^5.3.5", + "vite-plugin-static-copy": "^1.0.6", + "vite-plugin-wasm-pack": "^0.1.12", + "vite-tsconfig-paths": "^4.3.2" + }, + "displayName": "Shielder Wallet", + "description": "The best privacy wallet in the world", + "manifest": { + "host_permissions": [ + "https://*/*" + ], + "permissions": [ + "storage" + ], + "content_security_policy": { + "extension_pages": "script-src 'self' 'wasm-unsafe-eval'; object-src 'self';" + } + } +} diff --git a/ts/browser-extension/pnpm-lock.yaml b/ts/browser-extension/pnpm-lock.yaml new file mode 100644 index 00000000..a7de6fda --- /dev/null +++ b/ts/browser-extension/pnpm-lock.yaml @@ -0,0 +1,8982 @@ +lockfileVersion: '6.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +dependencies: + '@hookform/resolvers': + specifier: ^3.9.0 + version: 3.9.0(react-hook-form@7.53.0) + '@radix-ui/react-dialog': + specifier: ^1.1.1 + version: 1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-label': + specifier: ^2.1.0 + version: 2.1.0(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-slot': + specifier: ^1.1.0 + version: 1.1.0(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-switch': + specifier: ^1.1.0 + version: 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-toast': + specifier: ^1.2.1 + version: 1.2.1(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-tooltip': + specifier: ^1.1.2 + version: 1.1.2(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@tanstack/react-query': + specifier: ^5.55.3 + version: 5.56.2(react@18.3.1) + class-variance-authority: + specifier: ^0.7.0 + version: 0.7.0 + clsx: + specifier: ^2.1.1 + version: 2.1.1 + dotenv: + specifier: ^16.4.5 + version: 16.4.5 + eslint-plugin-import: + specifier: ^2.30.0 + version: 2.30.0(@typescript-eslint/parser@7.18.0)(eslint@8.57.0) + eslint-plugin-react: + specifier: ^7.35.2 + version: 7.35.2(eslint@8.57.0) + lucide-react: + specifier: ^0.407.0 + version: 0.407.0(react@18.3.1) + plasmo: + specifier: ^0.88.0 + version: 0.88.0(postcss@8.4.45)(react-dom@18.3.1)(react@18.3.1) + react: + specifier: ^18.3.1 + version: 18.3.1 + react-dom: + specifier: ^18.3.1 + version: 18.3.1(react@18.3.1) + react-hook-form: + specifier: ^7.52.2 + version: 7.53.0(react@18.3.1) + shielder-sdk: + specifier: link:../shielder-sdk + version: link:../shielder-sdk + tailwind-merge: + specifier: ^2.4.0 + version: 2.5.2 + tailwindcss-animate: + specifier: ^1.0.7 + version: 1.0.7(tailwindcss@3.4.10) + viem: + specifier: ^2.19.1 + version: 2.21.1(typescript@5.5.4)(zod@3.23.8) + vite-plugin-env-compatible: + specifier: ^2.0.1 + version: 2.0.1 + zod: + specifier: ^3.23.8 + version: 3.23.8 + +devDependencies: + '@tanstack/eslint-plugin-query': + specifier: ^5.51.15 + version: 5.53.0(eslint@8.57.0)(typescript@5.5.4) + '@types/chrome': + specifier: ^0.0.268 + version: 0.0.268 + '@types/node': + specifier: ^20.14.14 + version: 20.16.4 + '@types/react': + specifier: ^18.3.3 + version: 18.3.5 + '@types/react-dom': + specifier: ^18.3.0 + version: 18.3.0 + '@typescript-eslint/eslint-plugin': + specifier: ^7.18.0 + version: 7.18.0(@typescript-eslint/parser@7.18.0)(eslint@8.57.0)(typescript@5.5.4) + '@typescript-eslint/parser': + specifier: ^7.18.0 + version: 7.18.0(eslint@8.57.0)(typescript@5.5.4) + '@vitejs/plugin-react': + specifier: ^4.3.1 + version: 4.3.1(vite@5.4.3) + autoprefixer: + specifier: ^10.4.20 + version: 10.4.20(postcss@8.4.45) + eslint: + specifier: ^8.57.0 + version: 8.57.0 + eslint-plugin-react-hooks: + specifier: ^4.6.2 + version: 4.6.2(eslint@8.57.0) + eslint-plugin-react-refresh: + specifier: ^0.4.9 + version: 0.4.11(eslint@8.57.0) + postcss: + specifier: ^8.4.41 + version: 8.4.45 + tailwindcss: + specifier: ^3.4.7 + version: 3.4.10 + tsconfig-paths: + specifier: ^4.2.0 + version: 4.2.0 + tsx: + specifier: ^4.19.0 + version: 4.19.1 + typescript: + specifier: ^5.5.4 + version: 5.5.4 + vite: + specifier: ^5.3.5 + version: 5.4.3(@types/node@20.16.4) + vite-plugin-static-copy: + specifier: ^1.0.6 + version: 1.0.6(vite@5.4.3) + vite-plugin-wasm-pack: + specifier: ^0.1.12 + version: 0.1.12 + vite-tsconfig-paths: + specifier: ^4.3.2 + version: 4.3.2(typescript@5.5.4)(vite@5.4.3) + +packages: + + /@adraffy/ens-normalize@1.10.0: + resolution: {integrity: sha512-nA9XHtlAkYfJxY7bce8DcN7eKxWWCWkU+1GR9d+U6MbNpfwQp8TI7vqOsBsMcHoT4mBu2kypKoSKnghEzOOq5Q==} + dev: false + + /@alloc/quick-lru@5.2.0: + resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} + engines: {node: '>=10'} + + /@ampproject/remapping@2.3.0: + resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} + engines: {node: '>=6.0.0'} + dependencies: + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + + /@babel/code-frame@7.24.7: + resolution: {integrity: sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/highlight': 7.24.7 + picocolors: 1.1.0 + + /@babel/compat-data@7.25.4: + resolution: {integrity: sha512-+LGRog6RAsCJrrrg/IO6LGmpphNe5DiK30dGjCoxxeGv49B10/3XYGxPsAwrDlMFcFEvdAUavDT8r9k/hSyQqQ==} + engines: {node: '>=6.9.0'} + + /@babel/core@7.25.2: + resolution: {integrity: sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==} + engines: {node: '>=6.9.0'} + dependencies: + '@ampproject/remapping': 2.3.0 + '@babel/code-frame': 7.24.7 + '@babel/generator': 7.25.6 + '@babel/helper-compilation-targets': 7.25.2 + '@babel/helper-module-transforms': 7.25.2(@babel/core@7.25.2) + '@babel/helpers': 7.25.6 + '@babel/parser': 7.25.6 + '@babel/template': 7.25.0 + '@babel/traverse': 7.25.6 + '@babel/types': 7.25.6 + convert-source-map: 2.0.0 + debug: 4.3.6 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + /@babel/generator@7.25.6: + resolution: {integrity: sha512-VPC82gr1seXOpkjAAKoLhP50vx4vGNlF4msF64dSFq1P8RfB+QAuJWGHPXXPc8QyfVWwwB/TNNU4+ayZmHNbZw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.25.6 + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + jsesc: 2.5.2 + + /@babel/helper-compilation-targets@7.25.2: + resolution: {integrity: sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/compat-data': 7.25.4 + '@babel/helper-validator-option': 7.24.8 + browserslist: 4.23.3 + lru-cache: 5.1.1 + semver: 6.3.1 + + /@babel/helper-module-imports@7.24.7: + resolution: {integrity: sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/traverse': 7.25.6 + '@babel/types': 7.25.6 + transitivePeerDependencies: + - supports-color + + /@babel/helper-module-transforms@7.25.2(@babel/core@7.25.2): + resolution: {integrity: sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-module-imports': 7.24.7 + '@babel/helper-simple-access': 7.24.7 + '@babel/helper-validator-identifier': 7.24.7 + '@babel/traverse': 7.25.6 + transitivePeerDependencies: + - supports-color + + /@babel/helper-plugin-utils@7.24.8: + resolution: {integrity: sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helper-simple-access@7.24.7: + resolution: {integrity: sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/traverse': 7.25.6 + '@babel/types': 7.25.6 + transitivePeerDependencies: + - supports-color + + /@babel/helper-string-parser@7.24.8: + resolution: {integrity: sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==} + engines: {node: '>=6.9.0'} + + /@babel/helper-validator-identifier@7.24.7: + resolution: {integrity: sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==} + engines: {node: '>=6.9.0'} + + /@babel/helper-validator-option@7.24.8: + resolution: {integrity: sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==} + engines: {node: '>=6.9.0'} + + /@babel/helpers@7.25.6: + resolution: {integrity: sha512-Xg0tn4HcfTijTwfDwYlvVCl43V6h4KyVVX2aEm4qdO/PC6L2YvzLHFdmxhoeSA3eslcE6+ZVXHgWwopXYLNq4Q==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/template': 7.25.0 + '@babel/types': 7.25.6 + + /@babel/highlight@7.24.7: + resolution: {integrity: sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-validator-identifier': 7.24.7 + chalk: 2.4.2 + js-tokens: 4.0.0 + picocolors: 1.1.0 + + /@babel/parser@7.25.6: + resolution: {integrity: sha512-trGdfBdbD0l1ZPmcJ83eNxB9rbEax4ALFTF7fN386TMYbeCQbyme5cOEXQhbGXKebwGaB/J52w1mrklMcbgy6Q==} + engines: {node: '>=6.0.0'} + hasBin: true + dependencies: + '@babel/types': 7.25.6 + + /@babel/plugin-transform-react-jsx-self@7.24.7(@babel/core@7.25.2): + resolution: {integrity: sha512-fOPQYbGSgH0HUp4UJO4sMBFjY6DuWq+2i8rixyUMb3CdGixs/gccURvYOAhajBdKDoGajFr3mUq5rH3phtkGzw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + dev: true + + /@babel/plugin-transform-react-jsx-source@7.24.7(@babel/core@7.25.2): + resolution: {integrity: sha512-J2z+MWzZHVOemyLweMqngXrgGC42jQ//R0KdxqkIz/OrbVIIlhFI3WigZ5fO+nwFvBlncr4MGapd8vTyc7RPNQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + dev: true + + /@babel/runtime@7.25.6: + resolution: {integrity: sha512-VBj9MYyDb9tuLq7yzqjgzt6Q+IBQLrGZfdjOekyEirZPHxXWoTSGUTMrpsfi58Up73d13NfYLv8HT9vmznjzhQ==} + engines: {node: '>=6.9.0'} + dependencies: + regenerator-runtime: 0.14.1 + dev: false + + /@babel/template@7.25.0: + resolution: {integrity: sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.24.7 + '@babel/parser': 7.25.6 + '@babel/types': 7.25.6 + + /@babel/traverse@7.25.6: + resolution: {integrity: sha512-9Vrcx5ZW6UwK5tvqsj0nGpp/XzqthkT0dqIc9g1AdtygFToNtTF67XzYS//dm+SAK9cp3B9R4ZO/46p63SCjlQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.24.7 + '@babel/generator': 7.25.6 + '@babel/parser': 7.25.6 + '@babel/template': 7.25.0 + '@babel/types': 7.25.6 + debug: 4.3.6 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + + /@babel/types@7.25.6: + resolution: {integrity: sha512-/l42B1qxpG6RdfYf343Uw1vmDjeNhneUXtzhojE7pDgfpEypmRhI6j1kr17XCVv4Cgl9HdAiQY2x0GwKm7rWCw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-string-parser': 7.24.8 + '@babel/helper-validator-identifier': 7.24.7 + to-fast-properties: 2.0.0 + + /@esbuild/aix-ppc64@0.21.5: + resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [aix] + requiresBuild: true + dev: true + optional: true + + /@esbuild/aix-ppc64@0.23.1: + resolution: {integrity: sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-arm64@0.18.20: + resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: false + optional: true + + /@esbuild/android-arm64@0.21.5: + resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-arm64@0.23.1: + resolution: {integrity: sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-arm@0.18.20: + resolution: {integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: false + optional: true + + /@esbuild/android-arm@0.21.5: + resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-arm@0.23.1: + resolution: {integrity: sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-x64@0.18.20: + resolution: {integrity: sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + requiresBuild: true + dev: false + optional: true + + /@esbuild/android-x64@0.21.5: + resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-x64@0.23.1: + resolution: {integrity: sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-arm64@0.18.20: + resolution: {integrity: sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /@esbuild/darwin-arm64@0.21.5: + resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-arm64@0.23.1: + resolution: {integrity: sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-x64@0.18.20: + resolution: {integrity: sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /@esbuild/darwin-x64@0.21.5: + resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-x64@0.23.1: + resolution: {integrity: sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-arm64@0.18.20: + resolution: {integrity: sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: false + optional: true + + /@esbuild/freebsd-arm64@0.21.5: + resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-arm64@0.23.1: + resolution: {integrity: sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-x64@0.18.20: + resolution: {integrity: sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: false + optional: true + + /@esbuild/freebsd-x64@0.21.5: + resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-x64@0.23.1: + resolution: {integrity: sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm64@0.18.20: + resolution: {integrity: sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@esbuild/linux-arm64@0.21.5: + resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm64@0.23.1: + resolution: {integrity: sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm@0.18.20: + resolution: {integrity: sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@esbuild/linux-arm@0.21.5: + resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm@0.23.1: + resolution: {integrity: sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ia32@0.18.20: + resolution: {integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@esbuild/linux-ia32@0.21.5: + resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ia32@0.23.1: + resolution: {integrity: sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-loong64@0.18.20: + resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@esbuild/linux-loong64@0.21.5: + resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-loong64@0.23.1: + resolution: {integrity: sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-mips64el@0.18.20: + resolution: {integrity: sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@esbuild/linux-mips64el@0.21.5: + resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-mips64el@0.23.1: + resolution: {integrity: sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ppc64@0.18.20: + resolution: {integrity: sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@esbuild/linux-ppc64@0.21.5: + resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ppc64@0.23.1: + resolution: {integrity: sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-riscv64@0.18.20: + resolution: {integrity: sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@esbuild/linux-riscv64@0.21.5: + resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-riscv64@0.23.1: + resolution: {integrity: sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-s390x@0.18.20: + resolution: {integrity: sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@esbuild/linux-s390x@0.21.5: + resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-s390x@0.23.1: + resolution: {integrity: sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-x64@0.18.20: + resolution: {integrity: sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@esbuild/linux-x64@0.21.5: + resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-x64@0.23.1: + resolution: {integrity: sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/netbsd-x64@0.18.20: + resolution: {integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: false + optional: true + + /@esbuild/netbsd-x64@0.21.5: + resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/netbsd-x64@0.23.1: + resolution: {integrity: sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/openbsd-arm64@0.23.1: + resolution: {integrity: sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/openbsd-x64@0.18.20: + resolution: {integrity: sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: false + optional: true + + /@esbuild/openbsd-x64@0.21.5: + resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/openbsd-x64@0.23.1: + resolution: {integrity: sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/sunos-x64@0.18.20: + resolution: {integrity: sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: false + optional: true + + /@esbuild/sunos-x64@0.21.5: + resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: true + optional: true + + /@esbuild/sunos-x64@0.23.1: + resolution: {integrity: sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-arm64@0.18.20: + resolution: {integrity: sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /@esbuild/win32-arm64@0.21.5: + resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-arm64@0.23.1: + resolution: {integrity: sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-ia32@0.18.20: + resolution: {integrity: sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /@esbuild/win32-ia32@0.21.5: + resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-ia32@0.23.1: + resolution: {integrity: sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-x64@0.18.20: + resolution: {integrity: sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /@esbuild/win32-x64@0.21.5: + resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-x64@0.23.1: + resolution: {integrity: sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@eslint-community/eslint-utils@4.4.0(eslint@8.57.0): + resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + dependencies: + eslint: 8.57.0 + eslint-visitor-keys: 3.4.3 + + /@eslint-community/regexpp@4.11.0: + resolution: {integrity: sha512-G/M/tIiMrTAxEWRfLfQJMmGNX28IxBg4PBz8XqQhqUHLFI6TL2htpIB1iQCj144V5ee/JaKyT9/WZ0MGZWfA7A==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + /@eslint/eslintrc@2.1.4: + resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + ajv: 6.12.6 + debug: 4.3.6 + espree: 9.6.1 + globals: 13.24.0 + ignore: 5.3.2 + import-fresh: 3.3.0 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + /@eslint/js@8.57.0: + resolution: {integrity: sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + /@expo/spawn-async@1.7.2: + resolution: {integrity: sha512-QdWi16+CHB9JYP7gma19OVVg0BFkvU8zNj9GjWorYI8Iv8FUxjOCcYRuAmX4s/h91e4e7BPsskc8cSrZYho9Ew==} + engines: {node: '>=12'} + dependencies: + cross-spawn: 7.0.3 + dev: false + + /@floating-ui/core@1.6.7: + resolution: {integrity: sha512-yDzVT/Lm101nQ5TCVeK65LtdN7Tj4Qpr9RTXJ2vPFLqtLxwOrpoxAHAJI8J3yYWUc40J0BDBheaitK5SJmno2g==} + dependencies: + '@floating-ui/utils': 0.2.7 + dev: false + + /@floating-ui/dom@1.6.10: + resolution: {integrity: sha512-fskgCFv8J8OamCmyun8MfjB1Olfn+uZKjOKZ0vhYF3gRmEUXcGOjxWL8bBr7i4kIuPZ2KD2S3EUIOxnjC8kl2A==} + dependencies: + '@floating-ui/core': 1.6.7 + '@floating-ui/utils': 0.2.7 + dev: false + + /@floating-ui/react-dom@2.1.1(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-4h84MJt3CHrtG18mGsXuLCHMrug49d7DFkU0RMIyshRveBeyV2hmV/pDaF2Uxtu8kgq5r46llp5E5FQiR0K2Yg==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + dependencies: + '@floating-ui/dom': 1.6.10 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + dev: false + + /@floating-ui/utils@0.2.7: + resolution: {integrity: sha512-X8R8Oj771YRl/w+c1HqAC1szL8zWQRwFvgDwT129k9ACdBoud/+/rX9V0qiMl6LWUdP9voC2nDVZYPMQQsb6eA==} + dev: false + + /@hookform/resolvers@3.9.0(react-hook-form@7.53.0): + resolution: {integrity: sha512-bU0Gr4EepJ/EQsH/IwEzYLsT/PEj5C0ynLQ4m+GSHS+xKH4TfSelhluTgOaoc4kA5s7eCsQbM4wvZLzELmWzUg==} + peerDependencies: + react-hook-form: ^7.0.0 + dependencies: + react-hook-form: 7.53.0(react@18.3.1) + dev: false + + /@humanwhocodes/config-array@0.11.14: + resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} + engines: {node: '>=10.10.0'} + deprecated: Use @eslint/config-array instead + dependencies: + '@humanwhocodes/object-schema': 2.0.3 + debug: 4.3.6 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + + /@humanwhocodes/module-importer@1.0.1: + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + + /@humanwhocodes/object-schema@2.0.3: + resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} + deprecated: Use @eslint/object-schema instead + + /@isaacs/cliui@8.0.2: + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + dependencies: + string-width: 5.1.2 + string-width-cjs: /string-width@4.2.3 + strip-ansi: 7.1.0 + strip-ansi-cjs: /strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: /wrap-ansi@7.0.0 + + /@jridgewell/gen-mapping@0.3.5: + resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} + engines: {node: '>=6.0.0'} + dependencies: + '@jridgewell/set-array': 1.2.1 + '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/trace-mapping': 0.3.25 + + /@jridgewell/resolve-uri@3.1.2: + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + /@jridgewell/set-array@1.2.1: + resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} + engines: {node: '>=6.0.0'} + + /@jridgewell/sourcemap-codec@1.5.0: + resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + + /@jridgewell/trace-mapping@0.3.25: + resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.0 + + /@lezer/common@0.15.12: + resolution: {integrity: sha512-edfwCxNLnzq5pBA/yaIhwJ3U3Kz8VAUOTRg0hhxaizaI1N+qxV7EXDv/kLCkLeq2RzSFvxexlaj5Mzfn2kY0Ig==} + dev: false + + /@lezer/common@1.2.1: + resolution: {integrity: sha512-yemX0ZD2xS/73llMZIK6KplkjIjf2EvAHcinDi/TfJ9hS25G0388+ClHt6/3but0oOxinTcQHJLDXh6w1crzFQ==} + dev: false + + /@lezer/lr@0.15.8: + resolution: {integrity: sha512-bM6oE6VQZ6hIFxDNKk8bKPa14hqFrV07J/vHGOeiAbJReIaQXmkVb6xQu4MR+JBTLa5arGRyAAjJe1qaQt3Uvg==} + dependencies: + '@lezer/common': 0.15.12 + dev: false + + /@lezer/lr@1.4.2: + resolution: {integrity: sha512-pu0K1jCIdnQ12aWNaAVU5bzi7Bd1w54J3ECgANPmYLtQKP0HBj2cE/5coBD66MT10xbtIuUr7tg0Shbsvk0mDA==} + dependencies: + '@lezer/common': 1.2.1 + dev: false + + /@ljharb/through@2.3.13: + resolution: {integrity: sha512-/gKJun8NNiWGZJkGzI/Ragc53cOdcLNdzjLaIa+GEjguQs0ulsurx8WN0jijdK9yPqDvziX995sMRLyLt1uZMQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + dev: false + + /@lmdb/lmdb-darwin-arm64@2.5.2: + resolution: {integrity: sha512-+F8ioQIUN68B4UFiIBYu0QQvgb9FmlKw2ctQMSBfW2QBrZIxz9vD9jCGqTCPqZBRbPHAS/vG1zSXnKqnS2ch/A==} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /@lmdb/lmdb-darwin-arm64@2.7.11: + resolution: {integrity: sha512-r6+vYq2vKzE+vgj/rNVRMwAevq0+ZR9IeMFIqcSga+wMtMdXQ27KqQ7uS99/yXASg29bos7yHP3yk4x6Iio0lw==} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /@lmdb/lmdb-darwin-x64@2.5.2: + resolution: {integrity: sha512-KvPH56KRLLx4KSfKBx0m1r7GGGUMXm0jrKmNE7plbHlesZMuPJICtn07HYgQhj1LNsK7Yqwuvnqh1QxhJnF1EA==} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /@lmdb/lmdb-darwin-x64@2.7.11: + resolution: {integrity: sha512-jhj1aB4K8ycRL1HOQT5OtzlqOq70jxUQEWRN9Gqh3TIDN30dxXtiHi6EWF516tzw6v2+3QqhDMJh8O6DtTGG8Q==} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /@lmdb/lmdb-linux-arm64@2.5.2: + resolution: {integrity: sha512-aLl89VHL/wjhievEOlPocoefUyWdvzVrcQ/MHQYZm2JfV1jUsrbr/ZfkPPUFvZBf+VSE+Q0clWs9l29PCX1hTQ==} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@lmdb/lmdb-linux-arm64@2.7.11: + resolution: {integrity: sha512-7xGEfPPbmVJWcY2Nzqo11B9Nfxs+BAsiiaY/OcT4aaTDdykKeCjvKMQJA3KXCtZ1AtiC9ljyGLi+BfUwdulY5A==} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@lmdb/lmdb-linux-arm@2.5.2: + resolution: {integrity: sha512-5kQAP21hAkfW5Bl+e0P57dV4dGYnkNIpR7f/GAh6QHlgXx+vp/teVj4PGRZaKAvt0GX6++N6hF8NnGElLDuIDw==} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@lmdb/lmdb-linux-arm@2.7.11: + resolution: {integrity: sha512-dHfLFVSrw/v5X5lkwp0Vl7+NFpEeEYKfMG2DpdFJnnG1RgHQZngZxCaBagFoaJGykRpd2DYF1AeuXBFrAUAXfw==} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@lmdb/lmdb-linux-x64@2.5.2: + resolution: {integrity: sha512-xUdUfwDJLGjOUPH3BuPBt0NlIrR7f/QHKgu3GZIXswMMIihAekj2i97oI0iWG5Bok/b+OBjHPfa8IU9velnP/Q==} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@lmdb/lmdb-linux-x64@2.7.11: + resolution: {integrity: sha512-vUKI3JrREMQsXX8q0Eq5zX2FlYCKWMmLiCyyJNfZK0Uyf14RBg9VtB3ObQ41b4swYh2EWaltasWVe93Y8+KDng==} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@lmdb/lmdb-win32-x64@2.5.2: + resolution: {integrity: sha512-zrBczSbXKxEyK2ijtbRdICDygRqWSRPpZMN5dD1T8VMEW5RIhIbwFWw2phDRXuBQdVDpSjalCIUMWMV2h3JaZA==} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /@lmdb/lmdb-win32-x64@2.7.11: + resolution: {integrity: sha512-BJwkHlSUgtB+Ei52Ai32M1AOMerSlzyIGA/KC4dAGL+GGwVMdwG8HGCOA2TxP3KjhbgDPMYkv7bt/NmOmRIFng==} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /@mischnic/json-sourcemap@0.1.0: + resolution: {integrity: sha512-dQb3QnfNqmQNYA4nFSN/uLaByIic58gOXq4Y4XqLOWmOrw73KmJPt/HLyG0wvn1bnR6mBKs/Uwvkh+Hns1T0XA==} + engines: {node: '>=12.0.0'} + dependencies: + '@lezer/common': 0.15.12 + '@lezer/lr': 0.15.8 + json5: 2.2.3 + dev: false + + /@mischnic/json-sourcemap@0.1.1: + resolution: {integrity: sha512-iA7+tyVqfrATAIsIRWQG+a7ZLLD0VaOCKV2Wd/v4mqIU3J9c4jx9p7S0nw1XH3gJCKNBOOwACOPYYSUu9pgT+w==} + engines: {node: '>=12.0.0'} + dependencies: + '@lezer/common': 1.2.1 + '@lezer/lr': 1.4.2 + json5: 2.2.3 + dev: false + + /@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3: + resolution: {integrity: sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw==} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.3: + resolution: {integrity: sha512-mdzd3AVzYKuUmiWOQ8GNhl64/IoFGol569zNRdkLReh6LRLHOXxU4U8eq0JwaD8iFHdVGqSy4IjFL4reoWCDFw==} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.3: + resolution: {integrity: sha512-YxQL+ax0XqBJDZiKimS2XQaf+2wDGVa1enVRGzEvLLVFeqa5kx2bWbtcSXgsxjQB7nRqqIGFIcLteF/sHeVtQg==} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@msgpackr-extract/msgpackr-extract-linux-arm@3.0.3: + resolution: {integrity: sha512-fg0uy/dG/nZEXfYilKoRe7yALaNmHoYeIoJuJ7KJ+YyU2bvY8vPv27f7UKhGRpY6euFYqEVhxCFZgAUNQBM3nw==} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@msgpackr-extract/msgpackr-extract-linux-x64@3.0.3: + resolution: {integrity: sha512-cvwNfbP07pKUfq1uH+S6KJ7dT9K8WOE4ZiAcsrSes+UY55E/0jLYc+vq+DO7jlmqRb5zAggExKm0H7O/CBaesg==} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@msgpackr-extract/msgpackr-extract-win32-x64@3.0.3: + resolution: {integrity: sha512-x0fWaQtYp4E6sktbsdAqnehxDgEc/VwM7uLsRCYWaiGu0ykYdZPiS8zCWdnjHwyiumousxfBm4SO31eXqwEZhQ==} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /@noble/curves@1.4.0: + resolution: {integrity: sha512-p+4cb332SFCrReJkCYe8Xzm0OWi4Jji5jVdIZRL/PmacmDkFNw6MrrV+gGpiPxLHbV+zKFRywUWbaseT+tZRXg==} + dependencies: + '@noble/hashes': 1.4.0 + dev: false + + /@noble/hashes@1.4.0: + resolution: {integrity: sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==} + engines: {node: '>= 16'} + dev: false + + /@nodelib/fs.scandir@2.1.5: + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + /@nodelib/fs.stat@2.0.5: + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + /@nodelib/fs.walk@1.2.8: + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.17.1 + + /@parcel/bundler-default@2.9.3(@parcel/core@2.9.3): + resolution: {integrity: sha512-JjJK8dq39/UO/MWI/4SCbB1t/qgpQRFnFDetAAAezQ8oN++b24u1fkMDa/xqQGjbuPmGeTds5zxGgYs7id7PYg==} + engines: {node: '>= 12.0.0', parcel: ^2.9.3} + dependencies: + '@parcel/diagnostic': 2.9.3 + '@parcel/graph': 2.9.3 + '@parcel/hash': 2.9.3 + '@parcel/plugin': 2.9.3(@parcel/core@2.9.3) + '@parcel/utils': 2.9.3 + nullthrows: 1.1.1 + transitivePeerDependencies: + - '@parcel/core' + dev: false + + /@parcel/cache@2.8.3(@parcel/core@2.9.3): + resolution: {integrity: sha512-k7xv5vSQrJLdXuglo+Hv3yF4BCSs1tQ/8Vbd6CHTkOhf7LcGg6CPtLw053R/KdMpd/4GPn0QrAsOLdATm1ELtQ==} + engines: {node: '>= 12.0.0'} + peerDependencies: + '@parcel/core': ^2.8.3 + dependencies: + '@parcel/core': 2.9.3 + '@parcel/fs': 2.8.3(@parcel/core@2.9.3) + '@parcel/logger': 2.8.3 + '@parcel/utils': 2.8.3 + lmdb: 2.5.2 + dev: false + + /@parcel/cache@2.9.3(@parcel/core@2.9.3): + resolution: {integrity: sha512-Bj/H2uAJJSXtysG7E/x4EgTrE2hXmm7td/bc97K8M9N7+vQjxf7xb0ebgqe84ePVMkj4MVQSMEJkEucXVx4b0Q==} + engines: {node: '>= 12.0.0'} + peerDependencies: + '@parcel/core': ^2.9.3 + dependencies: + '@parcel/core': 2.9.3 + '@parcel/fs': 2.9.3(@parcel/core@2.9.3) + '@parcel/logger': 2.9.3 + '@parcel/utils': 2.9.3 + lmdb: 2.7.11 + dev: false + + /@parcel/codeframe@2.8.3: + resolution: {integrity: sha512-FE7sY53D6n/+2Pgg6M9iuEC6F5fvmyBkRE4d9VdnOoxhTXtkEqpqYgX7RJ12FAQwNlxKq4suBJQMgQHMF2Kjeg==} + engines: {node: '>= 12.0.0'} + dependencies: + chalk: 4.1.2 + dev: false + + /@parcel/codeframe@2.9.3: + resolution: {integrity: sha512-z7yTyD6h3dvduaFoHpNqur74/2yDWL++33rjQjIjCaXREBN6dKHoMGMizzo/i4vbiI1p9dDox2FIDEHCMQxqdA==} + engines: {node: '>= 12.0.0'} + dependencies: + chalk: 4.1.2 + dev: false + + /@parcel/compressor-raw@2.9.3(@parcel/core@2.9.3): + resolution: {integrity: sha512-jz3t4/ICMsHEqgiTmv5i1DJva2k5QRpZlBELVxfY+QElJTVe8edKJ0TiKcBxh2hx7sm4aUigGmp7JiqqHRRYmA==} + engines: {node: '>= 12.0.0', parcel: ^2.9.3} + dependencies: + '@parcel/plugin': 2.9.3(@parcel/core@2.9.3) + transitivePeerDependencies: + - '@parcel/core' + dev: false + + /@parcel/config-default@2.9.3(@parcel/core@2.9.3)(postcss@8.4.45)(typescript@5.2.2): + resolution: {integrity: sha512-tqN5tF7QnVABDZAu76co5E6N8mA9n8bxiWdK4xYyINYFIEHgX172oRTqXTnhEMjlMrdmASxvnGlbaPBaVnrCTw==} + peerDependencies: + '@parcel/core': ^2.9.3 + dependencies: + '@parcel/bundler-default': 2.9.3(@parcel/core@2.9.3) + '@parcel/compressor-raw': 2.9.3(@parcel/core@2.9.3) + '@parcel/core': 2.9.3 + '@parcel/namer-default': 2.9.3(@parcel/core@2.9.3) + '@parcel/optimizer-css': 2.9.3(@parcel/core@2.9.3) + '@parcel/optimizer-htmlnano': 2.9.3(@parcel/core@2.9.3)(postcss@8.4.45)(typescript@5.2.2) + '@parcel/optimizer-image': 2.9.3(@parcel/core@2.9.3) + '@parcel/optimizer-svgo': 2.9.3(@parcel/core@2.9.3) + '@parcel/optimizer-swc': 2.9.3(@parcel/core@2.9.3) + '@parcel/packager-css': 2.9.3(@parcel/core@2.9.3) + '@parcel/packager-html': 2.9.3(@parcel/core@2.9.3) + '@parcel/packager-js': 2.9.3(@parcel/core@2.9.3) + '@parcel/packager-raw': 2.9.3(@parcel/core@2.9.3) + '@parcel/packager-svg': 2.9.3(@parcel/core@2.9.3) + '@parcel/reporter-dev-server': 2.9.3(@parcel/core@2.9.3) + '@parcel/resolver-default': 2.9.3(@parcel/core@2.9.3) + '@parcel/runtime-browser-hmr': 2.9.3(@parcel/core@2.9.3) + '@parcel/runtime-js': 2.9.3(@parcel/core@2.9.3) + '@parcel/runtime-react-refresh': 2.9.3(@parcel/core@2.9.3) + '@parcel/runtime-service-worker': 2.9.3(@parcel/core@2.9.3) + '@parcel/transformer-babel': 2.9.3(@parcel/core@2.9.3) + '@parcel/transformer-css': 2.9.3(@parcel/core@2.9.3) + '@parcel/transformer-html': 2.9.3(@parcel/core@2.9.3) + '@parcel/transformer-image': 2.9.3(@parcel/core@2.9.3) + '@parcel/transformer-js': 2.9.3(@parcel/core@2.9.3) + '@parcel/transformer-json': 2.9.3(@parcel/core@2.9.3) + '@parcel/transformer-postcss': 2.9.3(@parcel/core@2.9.3) + '@parcel/transformer-posthtml': 2.9.3(@parcel/core@2.9.3) + '@parcel/transformer-raw': 2.9.3(@parcel/core@2.9.3) + '@parcel/transformer-react-refresh-wrap': 2.9.3(@parcel/core@2.9.3) + '@parcel/transformer-svg': 2.9.3(@parcel/core@2.9.3) + transitivePeerDependencies: + - '@swc/helpers' + - cssnano + - postcss + - purgecss + - relateurl + - srcset + - terser + - typescript + - uncss + dev: false + + /@parcel/core@2.9.3: + resolution: {integrity: sha512-4KlM1Zr/jpsqWuMXr2zmGsaOUs1zMMFh9vfCNKRZkptf+uk8I3sugHbNdo+F5B+4e2yMuOEb1zgAmvJLeuH6ww==} + engines: {node: '>= 12.0.0'} + dependencies: + '@mischnic/json-sourcemap': 0.1.1 + '@parcel/cache': 2.9.3(@parcel/core@2.9.3) + '@parcel/diagnostic': 2.9.3 + '@parcel/events': 2.9.3 + '@parcel/fs': 2.9.3(@parcel/core@2.9.3) + '@parcel/graph': 2.9.3 + '@parcel/hash': 2.9.3 + '@parcel/logger': 2.9.3 + '@parcel/package-manager': 2.9.3(@parcel/core@2.9.3) + '@parcel/plugin': 2.9.3(@parcel/core@2.9.3) + '@parcel/profiler': 2.9.3 + '@parcel/source-map': 2.1.1 + '@parcel/types': 2.9.3(@parcel/core@2.9.3) + '@parcel/utils': 2.9.3 + '@parcel/workers': 2.9.3(@parcel/core@2.9.3) + abortcontroller-polyfill: 1.7.5 + base-x: 3.0.10 + browserslist: 4.23.3 + clone: 2.1.2 + dotenv: 7.0.0 + dotenv-expand: 5.1.0 + json5: 2.2.3 + msgpackr: 1.11.0 + nullthrows: 1.1.1 + semver: 7.5.4 + dev: false + + /@parcel/diagnostic@2.8.3: + resolution: {integrity: sha512-u7wSzuMhLGWZjVNYJZq/SOViS3uFG0xwIcqXw12w54Uozd6BH8JlhVtVyAsq9kqnn7YFkw6pXHqAo5Tzh4FqsQ==} + engines: {node: '>= 12.0.0'} + dependencies: + '@mischnic/json-sourcemap': 0.1.1 + nullthrows: 1.1.1 + dev: false + + /@parcel/diagnostic@2.9.3: + resolution: {integrity: sha512-6jxBdyB3D7gP4iE66ghUGntWt2v64E6EbD4AetZk+hNJpgudOOPsKTovcMi/i7I4V0qD7WXSF4tvkZUoac0jwA==} + engines: {node: '>= 12.0.0'} + dependencies: + '@mischnic/json-sourcemap': 0.1.1 + nullthrows: 1.1.1 + dev: false + + /@parcel/events@2.8.3: + resolution: {integrity: sha512-hoIS4tAxWp8FJk3628bsgKxEvR7bq2scCVYHSqZ4fTi/s0+VymEATrRCUqf+12e5H47uw1/ZjoqrGtBI02pz4w==} + engines: {node: '>= 12.0.0'} + dev: false + + /@parcel/events@2.9.3: + resolution: {integrity: sha512-K0Scx+Bx9f9p1vuShMzNwIgiaZUkxEnexaKYHYemJrM7pMAqxIuIqhnvwurRCsZOVLUJPDDNJ626cWTc5vIq+A==} + engines: {node: '>= 12.0.0'} + dev: false + + /@parcel/fs-search@2.8.3: + resolution: {integrity: sha512-DJBT2N8knfN7Na6PP2mett3spQLTqxFrvl0gv+TJRp61T8Ljc4VuUTb0hqBj+belaASIp3Q+e8+SgaFQu7wLiQ==} + engines: {node: '>= 12.0.0'} + dependencies: + detect-libc: 1.0.3 + dev: false + + /@parcel/fs-search@2.9.3: + resolution: {integrity: sha512-nsNz3bsOpwS+jphcd+XjZL3F3PDq9lik0O8HPm5f6LYkqKWT+u/kgQzA8OkAHCR3q96LGiHxUywHPEBc27vI4Q==} + engines: {node: '>= 12.0.0'} + dev: false + + /@parcel/fs@2.8.3(@parcel/core@2.9.3): + resolution: {integrity: sha512-y+i+oXbT7lP0e0pJZi/YSm1vg0LDsbycFuHZIL80pNwdEppUAtibfJZCp606B7HOjMAlNZOBo48e3hPG3d8jgQ==} + engines: {node: '>= 12.0.0'} + peerDependencies: + '@parcel/core': ^2.8.3 + dependencies: + '@parcel/core': 2.9.3 + '@parcel/fs-search': 2.8.3 + '@parcel/types': 2.8.3(@parcel/core@2.9.3) + '@parcel/utils': 2.8.3 + '@parcel/watcher': 2.2.0 + '@parcel/workers': 2.8.3(@parcel/core@2.9.3) + dev: false + + /@parcel/fs@2.9.3(@parcel/core@2.9.3): + resolution: {integrity: sha512-/PrRKgCRw22G7rNPSpgN3Q+i2nIkZWuvIOAdMG4KWXC4XLp8C9jarNaWd5QEQ75amjhQSl3oUzABzkdCtkKrgg==} + engines: {node: '>= 12.0.0'} + peerDependencies: + '@parcel/core': ^2.9.3 + dependencies: + '@parcel/core': 2.9.3 + '@parcel/fs-search': 2.9.3 + '@parcel/types': 2.9.3(@parcel/core@2.9.3) + '@parcel/utils': 2.9.3 + '@parcel/watcher': 2.2.0 + '@parcel/workers': 2.9.3(@parcel/core@2.9.3) + dev: false + + /@parcel/graph@2.9.3: + resolution: {integrity: sha512-3LmRJmF8+OprAr6zJT3X2s8WAhLKkrhi6RsFlMWHifGU5ED1PFcJWFbOwJvSjcAhMQJP0fErcFIK1Ludv3Vm3g==} + engines: {node: '>= 12.0.0'} + dependencies: + nullthrows: 1.1.1 + dev: false + + /@parcel/hash@2.8.3: + resolution: {integrity: sha512-FVItqzjWmnyP4ZsVgX+G00+6U2IzOvqDtdwQIWisCcVoXJFCqZJDy6oa2qDDFz96xCCCynjRjPdQx2jYBCpfYw==} + engines: {node: '>= 12.0.0'} + dependencies: + detect-libc: 1.0.3 + xxhash-wasm: 0.4.2 + dev: false + + /@parcel/hash@2.9.3: + resolution: {integrity: sha512-qlH5B85XLzVAeijgKPjm1gQu35LoRYX/8igsjnN8vOlbc3O8BYAUIutU58fbHbtE8MJPbxQQUw7tkTjeoujcQQ==} + engines: {node: '>= 12.0.0'} + dependencies: + xxhash-wasm: 0.4.2 + dev: false + + /@parcel/logger@2.8.3: + resolution: {integrity: sha512-Kpxd3O/Vs7nYJIzkdmB6Bvp3l/85ydIxaZaPfGSGTYOfaffSOTkhcW9l6WemsxUrlts4za6CaEWcc4DOvaMOPA==} + engines: {node: '>= 12.0.0'} + dependencies: + '@parcel/diagnostic': 2.8.3 + '@parcel/events': 2.8.3 + dev: false + + /@parcel/logger@2.9.3: + resolution: {integrity: sha512-5FNBszcV6ilGFcijEOvoNVG6IUJGsnMiaEnGQs7Fvc1dktTjEddnoQbIYhcSZL63wEmzBZOgkT5yDMajJ/41jw==} + engines: {node: '>= 12.0.0'} + dependencies: + '@parcel/diagnostic': 2.9.3 + '@parcel/events': 2.9.3 + dev: false + + /@parcel/markdown-ansi@2.8.3: + resolution: {integrity: sha512-4v+pjyoh9f5zuU/gJlNvNFGEAb6J90sOBwpKJYJhdWXLZMNFCVzSigxrYO+vCsi8G4rl6/B2c0LcwIMjGPHmFQ==} + engines: {node: '>= 12.0.0'} + dependencies: + chalk: 4.1.2 + dev: false + + /@parcel/markdown-ansi@2.9.3: + resolution: {integrity: sha512-/Q4X8F2aN8UNjAJrQ5NfK2OmZf6shry9DqetUSEndQ0fHonk78WKt6LT0zSKEBEW/bB/bXk6mNMsCup6L8ibjQ==} + engines: {node: '>= 12.0.0'} + dependencies: + chalk: 4.1.2 + dev: false + + /@parcel/namer-default@2.9.3(@parcel/core@2.9.3): + resolution: {integrity: sha512-1ynFEcap48/Ngzwwn318eLYpLUwijuuZoXQPCsEQ21OOIOtfhFQJaPwXTsw6kRitshKq76P2aafE0BioGSqxcA==} + engines: {node: '>= 12.0.0', parcel: ^2.9.3} + dependencies: + '@parcel/diagnostic': 2.9.3 + '@parcel/plugin': 2.9.3(@parcel/core@2.9.3) + nullthrows: 1.1.1 + transitivePeerDependencies: + - '@parcel/core' + dev: false + + /@parcel/node-resolver-core@3.0.3(@parcel/core@2.9.3): + resolution: {integrity: sha512-AjxNcZVHHJoNT/A99PKIdFtwvoze8PAiC3yz8E/dRggrDIOboUEodeQYV5Aq++aK76uz/iOP0tST2T8A5rhb1A==} + engines: {node: '>= 12.0.0'} + dependencies: + '@mischnic/json-sourcemap': 0.1.1 + '@parcel/diagnostic': 2.9.3 + '@parcel/fs': 2.9.3(@parcel/core@2.9.3) + '@parcel/utils': 2.9.3 + nullthrows: 1.1.1 + semver: 7.5.4 + transitivePeerDependencies: + - '@parcel/core' + dev: false + + /@parcel/optimizer-css@2.9.3(@parcel/core@2.9.3): + resolution: {integrity: sha512-RK1QwcSdWDNUsFvuLy0hgnYKtPQebzCb0vPPzqs6LhL+vqUu9utOyRycGaQffHCkHVQP6zGlN+KFssd7YtFGhA==} + engines: {node: '>= 12.0.0', parcel: ^2.9.3} + dependencies: + '@parcel/diagnostic': 2.9.3 + '@parcel/plugin': 2.9.3(@parcel/core@2.9.3) + '@parcel/source-map': 2.1.1 + '@parcel/utils': 2.9.3 + browserslist: 4.23.3 + lightningcss: 1.26.0 + nullthrows: 1.1.1 + transitivePeerDependencies: + - '@parcel/core' + dev: false + + /@parcel/optimizer-data-url@2.9.3(@parcel/core@2.9.3): + resolution: {integrity: sha512-k8lOKLzgZ24JKOuyrNe5PptoH8GJ78AwnumG1xEOKZ77gZnUgdrn3XdjzE28ZqTI4LFkT3jApUiBKBmqnWDe7Q==} + engines: {node: '>= 12.0.0', parcel: ^2.9.3} + dependencies: + '@parcel/plugin': 2.9.3(@parcel/core@2.9.3) + '@parcel/utils': 2.9.3 + isbinaryfile: 4.0.10 + mime: 2.6.0 + transitivePeerDependencies: + - '@parcel/core' + dev: false + + /@parcel/optimizer-htmlnano@2.9.3(@parcel/core@2.9.3)(postcss@8.4.45)(typescript@5.2.2): + resolution: {integrity: sha512-9g/KBck3c6DokmJfvJ5zpHFBiCSolaGrcsTGx8C3YPdCTVTI9P1TDCwUxvAr4LjpcIRSa82wlLCI+nF6sSgxKA==} + engines: {node: '>= 12.0.0', parcel: ^2.9.3} + dependencies: + '@parcel/plugin': 2.9.3(@parcel/core@2.9.3) + htmlnano: 2.1.1(postcss@8.4.45)(svgo@2.8.0)(typescript@5.2.2) + nullthrows: 1.1.1 + posthtml: 0.16.6 + svgo: 2.8.0 + transitivePeerDependencies: + - '@parcel/core' + - cssnano + - postcss + - purgecss + - relateurl + - srcset + - terser + - typescript + - uncss + dev: false + + /@parcel/optimizer-image@2.9.3(@parcel/core@2.9.3): + resolution: {integrity: sha512-530YzthE7kmecnNhPbkAK+26yQNt69pfJrgE0Ev0BZaM1Wu2+33nki7o8qvkTkikhPrurEJLGIXt1qKmbKvCbA==} + engines: {node: '>= 12.0.0', parcel: ^2.9.3} + peerDependencies: + '@parcel/core': ^2.9.3 + dependencies: + '@parcel/core': 2.9.3 + '@parcel/diagnostic': 2.9.3 + '@parcel/plugin': 2.9.3(@parcel/core@2.9.3) + '@parcel/utils': 2.9.3 + '@parcel/workers': 2.9.3(@parcel/core@2.9.3) + dev: false + + /@parcel/optimizer-svgo@2.9.3(@parcel/core@2.9.3): + resolution: {integrity: sha512-ytQS0wY5JJhWU4mL0wfhYDUuHcfuw+Gy2+JcnTm1t1AZXHlOTbU6EzRWNqBShsgXjvdrQQXizAe3B6GFFlFJVQ==} + engines: {node: '>= 12.0.0', parcel: ^2.9.3} + dependencies: + '@parcel/diagnostic': 2.9.3 + '@parcel/plugin': 2.9.3(@parcel/core@2.9.3) + '@parcel/utils': 2.9.3 + svgo: 2.8.0 + transitivePeerDependencies: + - '@parcel/core' + dev: false + + /@parcel/optimizer-swc@2.9.3(@parcel/core@2.9.3): + resolution: {integrity: sha512-GQINNeqtdpL1ombq/Cpwi6IBk02wKJ/JJbYbyfHtk8lxlq13soenpwOlzJ5T9D2fdG+FUhai9NxpN5Ss4lNoAg==} + engines: {node: '>= 12.0.0', parcel: ^2.9.3} + dependencies: + '@parcel/diagnostic': 2.9.3 + '@parcel/plugin': 2.9.3(@parcel/core@2.9.3) + '@parcel/source-map': 2.1.1 + '@parcel/utils': 2.9.3 + '@swc/core': 1.7.23 + nullthrows: 1.1.1 + transitivePeerDependencies: + - '@parcel/core' + - '@swc/helpers' + dev: false + + /@parcel/package-manager@2.8.3(@parcel/core@2.9.3): + resolution: {integrity: sha512-tIpY5pD2lH53p9hpi++GsODy6V3khSTX4pLEGuMpeSYbHthnOViobqIlFLsjni+QA1pfc8NNNIQwSNdGjYflVA==} + engines: {node: '>= 12.0.0'} + peerDependencies: + '@parcel/core': ^2.8.3 + dependencies: + '@parcel/core': 2.9.3 + '@parcel/diagnostic': 2.8.3 + '@parcel/fs': 2.8.3(@parcel/core@2.9.3) + '@parcel/logger': 2.8.3 + '@parcel/types': 2.8.3(@parcel/core@2.9.3) + '@parcel/utils': 2.8.3 + '@parcel/workers': 2.8.3(@parcel/core@2.9.3) + semver: 5.7.2 + dev: false + + /@parcel/package-manager@2.9.3(@parcel/core@2.9.3): + resolution: {integrity: sha512-NH6omcNTEupDmW4Lm1e4NUYBjdqkURxgZ4CNESESInHJe6tblVhNB8Rpr1ar7zDar7cly9ILr8P6N3Ei7bTEjg==} + engines: {node: '>= 12.0.0'} + peerDependencies: + '@parcel/core': ^2.9.3 + dependencies: + '@parcel/core': 2.9.3 + '@parcel/diagnostic': 2.9.3 + '@parcel/fs': 2.9.3(@parcel/core@2.9.3) + '@parcel/logger': 2.9.3 + '@parcel/node-resolver-core': 3.0.3(@parcel/core@2.9.3) + '@parcel/types': 2.9.3(@parcel/core@2.9.3) + '@parcel/utils': 2.9.3 + '@parcel/workers': 2.9.3(@parcel/core@2.9.3) + semver: 7.5.4 + dev: false + + /@parcel/packager-css@2.9.3(@parcel/core@2.9.3): + resolution: {integrity: sha512-mePiWiYZOULY6e1RdAIJyRoYqXqGci0srOaVZYaP7mnrzvJgA63kaZFFsDiEWghunQpMUuUjM2x/vQVHzxmhKQ==} + engines: {node: '>= 12.0.0', parcel: ^2.9.3} + dependencies: + '@parcel/diagnostic': 2.9.3 + '@parcel/plugin': 2.9.3(@parcel/core@2.9.3) + '@parcel/source-map': 2.1.1 + '@parcel/utils': 2.9.3 + nullthrows: 1.1.1 + transitivePeerDependencies: + - '@parcel/core' + dev: false + + /@parcel/packager-html@2.9.3(@parcel/core@2.9.3): + resolution: {integrity: sha512-0Ex+O0EaZf9APNERRNGgGto02hFJ6f5RQEvRWBK55WAV1rXeU+kpjC0c0qZvnUaUtXfpWMsEBkevJCwDkUMeMg==} + engines: {node: '>= 12.0.0', parcel: ^2.9.3} + dependencies: + '@parcel/plugin': 2.9.3(@parcel/core@2.9.3) + '@parcel/types': 2.9.3(@parcel/core@2.9.3) + '@parcel/utils': 2.9.3 + nullthrows: 1.1.1 + posthtml: 0.16.6 + transitivePeerDependencies: + - '@parcel/core' + dev: false + + /@parcel/packager-js@2.9.3(@parcel/core@2.9.3): + resolution: {integrity: sha512-V5xwkoE3zQ3R+WqAWhA1KGQ791FvJeW6KonOlMI1q76Djjgox68hhObqcLu66AmYNhR2R/wUpkP18hP2z8dSFw==} + engines: {node: '>= 12.0.0', parcel: ^2.9.3} + dependencies: + '@parcel/diagnostic': 2.9.3 + '@parcel/hash': 2.9.3 + '@parcel/plugin': 2.9.3(@parcel/core@2.9.3) + '@parcel/source-map': 2.1.1 + '@parcel/utils': 2.9.3 + globals: 13.24.0 + nullthrows: 1.1.1 + transitivePeerDependencies: + - '@parcel/core' + dev: false + + /@parcel/packager-raw@2.9.3(@parcel/core@2.9.3): + resolution: {integrity: sha512-oPQTNoYanQ2DdJyL61uPYK2py83rKOT8YVh2QWAx0zsSli6Kiy64U3+xOCYWgDVCrHw9+9NpQMuAdSiFg4cq8g==} + engines: {node: '>= 12.0.0', parcel: ^2.9.3} + dependencies: + '@parcel/plugin': 2.9.3(@parcel/core@2.9.3) + transitivePeerDependencies: + - '@parcel/core' + dev: false + + /@parcel/packager-svg@2.9.3(@parcel/core@2.9.3): + resolution: {integrity: sha512-p/Ya6UO9DAkaCUFxfFGyeHZDp9YPAlpdnh1OChuwqSFOXFjjeXuoK4KLT+ZRalVBo2Jo8xF70oKMZw4MVvaL7Q==} + engines: {node: '>= 12.0.0', parcel: ^2.9.3} + dependencies: + '@parcel/plugin': 2.9.3(@parcel/core@2.9.3) + '@parcel/types': 2.9.3(@parcel/core@2.9.3) + '@parcel/utils': 2.9.3 + posthtml: 0.16.6 + transitivePeerDependencies: + - '@parcel/core' + dev: false + + /@parcel/plugin@2.8.3(@parcel/core@2.9.3): + resolution: {integrity: sha512-jZ6mnsS4D9X9GaNnvrixDQwlUQJCohDX2hGyM0U0bY2NWU8Km97SjtoCpWjq+XBCx/gpC4g58+fk9VQeZq2vlw==} + engines: {node: '>= 12.0.0'} + dependencies: + '@parcel/types': 2.8.3(@parcel/core@2.9.3) + transitivePeerDependencies: + - '@parcel/core' + dev: false + + /@parcel/plugin@2.9.3(@parcel/core@2.9.3): + resolution: {integrity: sha512-qN85Gqr2GMuxX1dT1mnuO9hOcvlEv1lrYrCxn7CJN2nUhbwcfG+LEvcrCzCOJ6XtIHm+ZBV9h9p7FfoPLvpw+g==} + engines: {node: '>= 12.0.0'} + dependencies: + '@parcel/types': 2.9.3(@parcel/core@2.9.3) + transitivePeerDependencies: + - '@parcel/core' + dev: false + + /@parcel/profiler@2.9.3: + resolution: {integrity: sha512-pyHc9lw8VZDfgZoeZWZU9J0CVEv1Zw9O5+e0DJPDPHuXJYr72ZAOhbljtU3owWKAeW+++Q2AZWkbUGEOjI/e6g==} + engines: {node: '>= 12.0.0'} + dependencies: + '@parcel/diagnostic': 2.9.3 + '@parcel/events': 2.9.3 + chrome-trace-event: 1.0.4 + dev: false + + /@parcel/reporter-bundle-buddy@2.9.3(@parcel/core@2.9.3): + resolution: {integrity: sha512-9ftzLZ161USdvnxueT55EWufLI48va0xJfB5MAJLG92VAS1N1FSFgYKdkGFzBKw0eK9UScQNYnntCGC17rBayQ==} + engines: {node: '>= 12.0.0', parcel: ^2.9.3} + dependencies: + '@parcel/plugin': 2.9.3(@parcel/core@2.9.3) + transitivePeerDependencies: + - '@parcel/core' + dev: false + + /@parcel/reporter-dev-server@2.9.3(@parcel/core@2.9.3): + resolution: {integrity: sha512-s6eboxdLEtRSvG52xi9IiNbcPKC0XMVmvTckieue2EqGDbDcaHQoHmmwkk0rNq0/Z/UxelGcQXoIYC/0xq3ykQ==} + engines: {node: '>= 12.0.0', parcel: ^2.9.3} + dependencies: + '@parcel/plugin': 2.9.3(@parcel/core@2.9.3) + '@parcel/utils': 2.9.3 + transitivePeerDependencies: + - '@parcel/core' + dev: false + + /@parcel/resolver-default@2.9.3(@parcel/core@2.9.3): + resolution: {integrity: sha512-8ESJk1COKvDzkmOnppNXoDamNMlYVIvrKc2RuFPmp8nKVj47R6NwMgvwxEaatyPzvkmyTpq5RvG9I3HFc+r4Cw==} + engines: {node: '>= 12.0.0', parcel: ^2.9.3} + dependencies: + '@parcel/node-resolver-core': 3.0.3(@parcel/core@2.9.3) + '@parcel/plugin': 2.9.3(@parcel/core@2.9.3) + transitivePeerDependencies: + - '@parcel/core' + dev: false + + /@parcel/runtime-browser-hmr@2.9.3(@parcel/core@2.9.3): + resolution: {integrity: sha512-EgiDIDrVAWpz7bOzWXqVinQkaFjLwT34wsonpXAbuI7f7r00d52vNAQC9AMu+pTijA3gyKoJ+Q4NWPMZf7ACDA==} + engines: {node: '>= 12.0.0', parcel: ^2.9.3} + dependencies: + '@parcel/plugin': 2.9.3(@parcel/core@2.9.3) + '@parcel/utils': 2.9.3 + transitivePeerDependencies: + - '@parcel/core' + dev: false + + /@parcel/runtime-js@2.8.3(@parcel/core@2.9.3): + resolution: {integrity: sha512-IRja0vNKwvMtPgIqkBQh0QtRn0XcxNC8HU1jrgWGRckzu10qJWO+5ULgtOeR4pv9krffmMPqywGXw6l/gvJKYQ==} + engines: {node: '>= 12.0.0', parcel: ^2.8.3} + dependencies: + '@parcel/plugin': 2.8.3(@parcel/core@2.9.3) + '@parcel/utils': 2.8.3 + nullthrows: 1.1.1 + transitivePeerDependencies: + - '@parcel/core' + dev: false + + /@parcel/runtime-js@2.9.3(@parcel/core@2.9.3): + resolution: {integrity: sha512-EvIy+qXcKnB5qxHhe96zmJpSAViNVXHfQI5RSdZ2a7CPwORwhTI+zPNT9sb7xb/WwFw/WuTTgzT40b41DceU6Q==} + engines: {node: '>= 12.0.0', parcel: ^2.9.3} + dependencies: + '@parcel/diagnostic': 2.9.3 + '@parcel/plugin': 2.9.3(@parcel/core@2.9.3) + '@parcel/utils': 2.9.3 + nullthrows: 1.1.1 + transitivePeerDependencies: + - '@parcel/core' + dev: false + + /@parcel/runtime-react-refresh@2.9.3(@parcel/core@2.9.3): + resolution: {integrity: sha512-XBgryZQIyCmi6JwEfMUCmINB3l1TpTp9a2iFxmYNpzHlqj4Ve0saKaqWOVRLvC945ZovWIBzcSW2IYqWKGtbAA==} + engines: {node: '>= 12.0.0', parcel: ^2.9.3} + dependencies: + '@parcel/plugin': 2.9.3(@parcel/core@2.9.3) + '@parcel/utils': 2.9.3 + react-error-overlay: 6.0.9 + react-refresh: 0.9.0 + transitivePeerDependencies: + - '@parcel/core' + dev: false + + /@parcel/runtime-service-worker@2.9.3(@parcel/core@2.9.3): + resolution: {integrity: sha512-qLJLqv1mMdWL7gyh8aKBFFAuEiJkhUUgLKpdn6eSfH/R7kTtb76WnOwqUrhvEI9bZFUM/8Pa1bzJnPpqSOM+Sw==} + engines: {node: '>= 12.0.0', parcel: ^2.9.3} + dependencies: + '@parcel/plugin': 2.9.3(@parcel/core@2.9.3) + '@parcel/utils': 2.9.3 + nullthrows: 1.1.1 + transitivePeerDependencies: + - '@parcel/core' + dev: false + + /@parcel/source-map@2.1.1: + resolution: {integrity: sha512-Ejx1P/mj+kMjQb8/y5XxDUn4reGdr+WyKYloBljpppUy8gs42T+BNoEOuRYqDVdgPc6NxduzIDoJS9pOFfV5Ew==} + engines: {node: ^12.18.3 || >=14} + dependencies: + detect-libc: 1.0.3 + dev: false + + /@parcel/transformer-babel@2.9.3(@parcel/core@2.9.3): + resolution: {integrity: sha512-pURtEsnsp3h6tOBDuzh9wRvVtw4PgIlqwAArIWdrG7iwqOUYv9D8ME4+ePWEu7MQWAp58hv9pTJtqWv4T+Sq8A==} + engines: {node: '>= 12.0.0', parcel: ^2.9.3} + dependencies: + '@parcel/diagnostic': 2.9.3 + '@parcel/plugin': 2.9.3(@parcel/core@2.9.3) + '@parcel/source-map': 2.1.1 + '@parcel/utils': 2.9.3 + browserslist: 4.23.3 + json5: 2.2.3 + nullthrows: 1.1.1 + semver: 7.5.4 + transitivePeerDependencies: + - '@parcel/core' + dev: false + + /@parcel/transformer-css@2.9.3(@parcel/core@2.9.3): + resolution: {integrity: sha512-duWMdbEBBPjg3fQdXF16iWIdThetDZvCs2TpUD7xOlXH6kR0V5BJy8ONFT15u1RCqIV9hSNGaS3v3I9YRNY5zQ==} + engines: {node: '>= 12.0.0', parcel: ^2.9.3} + dependencies: + '@parcel/diagnostic': 2.9.3 + '@parcel/plugin': 2.9.3(@parcel/core@2.9.3) + '@parcel/source-map': 2.1.1 + '@parcel/utils': 2.9.3 + browserslist: 4.23.3 + lightningcss: 1.26.0 + nullthrows: 1.1.1 + transitivePeerDependencies: + - '@parcel/core' + dev: false + + /@parcel/transformer-graphql@2.9.3(@parcel/core@2.9.3): + resolution: {integrity: sha512-cIohsH3WlXgn63baU35ZoWHzttmkyE2Q1pexKjszODzSUq3pdcg+9k4rB/z8GGMzXvFRYuBgl2M2Ukqz7SueMg==} + engines: {node: '>= 12.0.0', parcel: ^2.9.3} + dependencies: + '@parcel/plugin': 2.9.3(@parcel/core@2.9.3) + graphql: 15.9.0 + graphql-import-macro: 1.0.0 + transitivePeerDependencies: + - '@parcel/core' + dev: false + + /@parcel/transformer-html@2.9.3(@parcel/core@2.9.3): + resolution: {integrity: sha512-0NU4omcHzFXA1seqftAXA2KNZaMByoKaNdXnLgBgtCGDiYvOcL+6xGHgY6pw9LvOh5um10KI5TxSIMILoI7VtA==} + engines: {node: '>= 12.0.0', parcel: ^2.9.3} + dependencies: + '@parcel/diagnostic': 2.9.3 + '@parcel/hash': 2.9.3 + '@parcel/plugin': 2.9.3(@parcel/core@2.9.3) + nullthrows: 1.1.1 + posthtml: 0.16.6 + posthtml-parser: 0.10.2 + posthtml-render: 3.0.0 + semver: 7.5.4 + srcset: 4.0.0 + transitivePeerDependencies: + - '@parcel/core' + dev: false + + /@parcel/transformer-image@2.9.3(@parcel/core@2.9.3): + resolution: {integrity: sha512-7CEe35RaPadQzLIuxzTtIxnItvOoy46hcbXtOdDt6lmVa4omuOygZYRIya2lsGIP4JHvAaALMb5nt99a1uTwJg==} + engines: {node: '>= 12.0.0', parcel: ^2.9.3} + peerDependencies: + '@parcel/core': ^2.9.3 + dependencies: + '@parcel/core': 2.9.3 + '@parcel/plugin': 2.9.3(@parcel/core@2.9.3) + '@parcel/utils': 2.9.3 + '@parcel/workers': 2.9.3(@parcel/core@2.9.3) + nullthrows: 1.1.1 + dev: false + + /@parcel/transformer-inline-string@2.9.3(@parcel/core@2.9.3): + resolution: {integrity: sha512-IZNd0Ksl32psX1M41KbUc4BmvVSoLVnlpaMrh9C/l+piFSkDXWMnF0PONX/RcxYMBIwB2jYllheIKH54naeNaA==} + engines: {node: '>= 12.0.0', parcel: ^2.9.3} + dependencies: + '@parcel/plugin': 2.9.3(@parcel/core@2.9.3) + transitivePeerDependencies: + - '@parcel/core' + dev: false + + /@parcel/transformer-js@2.9.3(@parcel/core@2.9.3): + resolution: {integrity: sha512-Z2MVVg5FYcPOfxlUwxqb5l9yjTMEqE3KI3zq2MBRUme6AV07KxLmCDF23b6glzZlHWQUE8MXzYCTAkOPCcPz+Q==} + engines: {node: '>= 12.0.0', parcel: ^2.9.3} + peerDependencies: + '@parcel/core': ^2.9.3 + dependencies: + '@parcel/core': 2.9.3 + '@parcel/diagnostic': 2.9.3 + '@parcel/plugin': 2.9.3(@parcel/core@2.9.3) + '@parcel/source-map': 2.1.1 + '@parcel/utils': 2.9.3 + '@parcel/workers': 2.9.3(@parcel/core@2.9.3) + '@swc/helpers': 0.5.13 + browserslist: 4.23.3 + nullthrows: 1.1.1 + regenerator-runtime: 0.13.11 + semver: 7.5.4 + dev: false + + /@parcel/transformer-json@2.9.3(@parcel/core@2.9.3): + resolution: {integrity: sha512-yNL27dbOLhkkrjaQjiQ7Im9VOxmkfuuSNSmS0rA3gEjVcm07SLKRzWkAaPnyx44Lb6bzyOTWwVrb9aMmxgADpA==} + engines: {node: '>= 12.0.0', parcel: ^2.9.3} + dependencies: + '@parcel/plugin': 2.9.3(@parcel/core@2.9.3) + json5: 2.2.3 + transitivePeerDependencies: + - '@parcel/core' + dev: false + + /@parcel/transformer-less@2.9.3(@parcel/core@2.9.3): + resolution: {integrity: sha512-qwF5NQ8rPZjS79tv9RRPxzkZcwLcI4Xg2gHm9c1PvsgoaL2tVNpfjiRA6MOrzfJp+xr7xEzeMDZksOJ1WQiiQg==} + engines: {node: '>= 12.0.0', parcel: ^2.9.3} + dependencies: + '@parcel/plugin': 2.9.3(@parcel/core@2.9.3) + '@parcel/source-map': 2.1.1 + less: 4.2.0 + transitivePeerDependencies: + - '@parcel/core' + dev: false + + /@parcel/transformer-postcss@2.9.3(@parcel/core@2.9.3): + resolution: {integrity: sha512-HoDvPqKzhpmvMmHqQhDnt8F1vH61m6plpGiYaYnYv2Om4HHi5ZIq9bO+9QLBnTKfaZ7ndYSefTKOxTYElg7wyw==} + engines: {node: '>= 12.0.0', parcel: ^2.9.3} + dependencies: + '@parcel/diagnostic': 2.9.3 + '@parcel/hash': 2.9.3 + '@parcel/plugin': 2.9.3(@parcel/core@2.9.3) + '@parcel/utils': 2.9.3 + clone: 2.1.2 + nullthrows: 1.1.1 + postcss-value-parser: 4.2.0 + semver: 7.5.4 + transitivePeerDependencies: + - '@parcel/core' + dev: false + + /@parcel/transformer-posthtml@2.9.3(@parcel/core@2.9.3): + resolution: {integrity: sha512-2fQGgrzRmaqbWf3y2/T6xhqrNjzqMMKksqJzvc8TMfK6f2kg3Ddjv158eaSW2JdkV39aY7tvAOn5f1uzo74BMA==} + engines: {node: '>= 12.0.0', parcel: ^2.9.3} + dependencies: + '@parcel/plugin': 2.9.3(@parcel/core@2.9.3) + '@parcel/utils': 2.9.3 + nullthrows: 1.1.1 + posthtml: 0.16.6 + posthtml-parser: 0.10.2 + posthtml-render: 3.0.0 + semver: 7.5.4 + transitivePeerDependencies: + - '@parcel/core' + dev: false + + /@parcel/transformer-raw@2.9.3(@parcel/core@2.9.3): + resolution: {integrity: sha512-oqdPzMC9QzWRbY9J6TZEqltknjno+dY24QWqf8ondmdF2+W+/2mRDu59hhCzQrqUHgTq4FewowRZmSfpzHxwaQ==} + engines: {node: '>= 12.0.0', parcel: ^2.9.3} + dependencies: + '@parcel/plugin': 2.9.3(@parcel/core@2.9.3) + transitivePeerDependencies: + - '@parcel/core' + dev: false + + /@parcel/transformer-react-refresh-wrap@2.9.3(@parcel/core@2.9.3): + resolution: {integrity: sha512-cb9NyU6oJlDblFIlzqIE8AkvRQVGl2IwJNKwD4PdE7Y6sq2okGEPG4hOw3k/Y9JVjM4/2pUORqvjSRhWwd9oVQ==} + engines: {node: '>= 12.0.0', parcel: ^2.9.3} + dependencies: + '@parcel/plugin': 2.9.3(@parcel/core@2.9.3) + '@parcel/utils': 2.9.3 + react-refresh: 0.9.0 + transitivePeerDependencies: + - '@parcel/core' + dev: false + + /@parcel/transformer-sass@2.9.3(@parcel/core@2.9.3): + resolution: {integrity: sha512-i9abj9bKg3xCHghJyTM3rUVxIEn9n1Rl+DFdpyNAD8VZ52COfOshFDQOWNuhU1hEnJOFYCjnfcO0HRTsg3dWmg==} + engines: {node: '>= 12.0.0', parcel: ^2.9.3} + dependencies: + '@parcel/plugin': 2.9.3(@parcel/core@2.9.3) + '@parcel/source-map': 2.1.1 + sass: 1.78.0 + transitivePeerDependencies: + - '@parcel/core' + dev: false + + /@parcel/transformer-svg-react@2.9.3(@parcel/core@2.9.3): + resolution: {integrity: sha512-RXmCn58CkCBhpsS1AaRBrSRla0U5JN3r3hb7kQvEb+d7chGnsxCCWsBxtlrxPUjoUFLdQli9rhpCTkiyOBXY2A==} + engines: {node: '>= 12.0.0', parcel: ^2.9.3} + dependencies: + '@parcel/plugin': 2.9.3(@parcel/core@2.9.3) + '@svgr/core': 6.5.1 + '@svgr/plugin-jsx': 6.5.1(@svgr/core@6.5.1) + '@svgr/plugin-svgo': 6.5.1(@svgr/core@6.5.1) + transitivePeerDependencies: + - '@parcel/core' + - supports-color + dev: false + + /@parcel/transformer-svg@2.9.3(@parcel/core@2.9.3): + resolution: {integrity: sha512-ypmE+dzB09IMCdEAkOsSxq1dEIm2A3h67nAFz4qbfHbwNgXBUuy/jB3ZMwXN/cO0f7SBh/Ap8Jhq6vmGqB5tWw==} + engines: {node: '>= 12.0.0', parcel: ^2.9.3} + dependencies: + '@parcel/diagnostic': 2.9.3 + '@parcel/hash': 2.9.3 + '@parcel/plugin': 2.9.3(@parcel/core@2.9.3) + nullthrows: 1.1.1 + posthtml: 0.16.6 + posthtml-parser: 0.10.2 + posthtml-render: 3.0.0 + semver: 7.5.4 + transitivePeerDependencies: + - '@parcel/core' + dev: false + + /@parcel/transformer-worklet@2.9.3(@parcel/core@2.9.3): + resolution: {integrity: sha512-Fgd81OTOvAxAKoBGsQow/mgxELaNG1FeZW4DuDEPo/hR3lbs90oYuVpG2thdx7hmi/W6xqhrLaEN5Ea1v0LvEA==} + engines: {node: '>= 12.0.0', parcel: ^2.9.3} + dependencies: + '@parcel/plugin': 2.9.3(@parcel/core@2.9.3) + transitivePeerDependencies: + - '@parcel/core' + dev: false + + /@parcel/types@2.8.3(@parcel/core@2.9.3): + resolution: {integrity: sha512-FECA1FB7+0UpITKU0D6TgGBpGxYpVSMNEENZbSJxFSajNy3wrko+zwBKQmFOLOiPcEtnGikxNs+jkFWbPlUAtw==} + dependencies: + '@parcel/cache': 2.8.3(@parcel/core@2.9.3) + '@parcel/diagnostic': 2.8.3 + '@parcel/fs': 2.8.3(@parcel/core@2.9.3) + '@parcel/package-manager': 2.8.3(@parcel/core@2.9.3) + '@parcel/source-map': 2.1.1 + '@parcel/workers': 2.8.3(@parcel/core@2.9.3) + utility-types: 3.11.0 + transitivePeerDependencies: + - '@parcel/core' + dev: false + + /@parcel/types@2.9.3(@parcel/core@2.9.3): + resolution: {integrity: sha512-NSNY8sYtRhvF1SqhnIGgGvJocyWt1K8Tnw5cVepm0g38ywtX6mwkBvMkmeehXkII4mSUn+frD9wGsydTunezvA==} + dependencies: + '@parcel/cache': 2.9.3(@parcel/core@2.9.3) + '@parcel/diagnostic': 2.9.3 + '@parcel/fs': 2.9.3(@parcel/core@2.9.3) + '@parcel/package-manager': 2.9.3(@parcel/core@2.9.3) + '@parcel/source-map': 2.1.1 + '@parcel/workers': 2.9.3(@parcel/core@2.9.3) + utility-types: 3.11.0 + transitivePeerDependencies: + - '@parcel/core' + dev: false + + /@parcel/utils@2.8.3: + resolution: {integrity: sha512-IhVrmNiJ+LOKHcCivG5dnuLGjhPYxQ/IzbnF2DKNQXWBTsYlHkJZpmz7THoeLtLliGmSOZ3ZCsbR8/tJJKmxjA==} + engines: {node: '>= 12.0.0'} + dependencies: + '@parcel/codeframe': 2.8.3 + '@parcel/diagnostic': 2.8.3 + '@parcel/hash': 2.8.3 + '@parcel/logger': 2.8.3 + '@parcel/markdown-ansi': 2.8.3 + '@parcel/source-map': 2.1.1 + chalk: 4.1.2 + dev: false + + /@parcel/utils@2.9.3: + resolution: {integrity: sha512-cesanjtj/oLehW8Waq9JFPmAImhoiHX03ihc3JTWkrvJYSbD7wYKCDgPAM3JiRAqvh1LZ6P699uITrYWNoRLUg==} + engines: {node: '>= 12.0.0'} + dependencies: + '@parcel/codeframe': 2.9.3 + '@parcel/diagnostic': 2.9.3 + '@parcel/hash': 2.9.3 + '@parcel/logger': 2.9.3 + '@parcel/markdown-ansi': 2.9.3 + '@parcel/source-map': 2.1.1 + chalk: 4.1.2 + nullthrows: 1.1.1 + dev: false + + /@parcel/watcher-android-arm64@2.2.0: + resolution: {integrity: sha512-nU2wh00CTQT9rr1TIKTjdQ9lAGYpmz6XuKw0nAwAN+S2A5YiD55BK1u+E5WMCT8YOIDe/n6gaj4o/Bi9294SSQ==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: false + optional: true + + /@parcel/watcher-darwin-arm64@2.2.0: + resolution: {integrity: sha512-cJl0UZDcodciy3TDMomoK/Huxpjlkkim3SyMgWzjovHGOZKNce9guLz2dzuFwfObBFCjfznbFMIvAZ5syXotYw==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /@parcel/watcher-darwin-x64@2.2.0: + resolution: {integrity: sha512-QI77zxaGrCV1StKcoRYfsUfmUmvPMPfQrubkBBy5XujV2fwaLgZivQOTQMBgp5K2+E19u1ufpspKXAPqSzpbyg==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /@parcel/watcher-linux-arm-glibc@2.2.0: + resolution: {integrity: sha512-I2GPBcAXazPzabCmfsa3HRRW+MGlqxYd8g8RIueJU+a4o5nyNZDz0CR1cu0INT0QSQXEZV7w6UE8Hz9CF8u3Pg==} + engines: {node: '>= 10.0.0'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@parcel/watcher-linux-arm64-glibc@2.2.0: + resolution: {integrity: sha512-St5mlfp+2lS9AmgixUqfwJa/DwVmTCJxC1HcOubUTz6YFOKIlkHCeUa1Bxi4E/tR/HSez8+heXHL8HQkJ4Bd8g==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@parcel/watcher-linux-arm64-musl@2.2.0: + resolution: {integrity: sha512-jS+qfhhoOBVWwMLP65MaG8xdInMK30pPW8wqTCg2AAuVJh5xepMbzkhHJ4zURqHiyY3EiIRuYu4ONJKCxt8iqA==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@parcel/watcher-linux-x64-glibc@2.2.0: + resolution: {integrity: sha512-xJvJ7R2wJdi47WZBFS691RDOWvP1j/IAs3EXaWVhDI8FFITbWrWaln7KoNcR0Y3T+ZwimFY/cfb0PNht1q895g==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@parcel/watcher-linux-x64-musl@2.2.0: + resolution: {integrity: sha512-D+NMpgr23a+RI5mu8ZPKWy7AqjBOkURFDgP5iIXXEf/K3hm0jJ3ogzi0Ed2237B/CdYREimCgXyeiAlE/FtwyA==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@parcel/watcher-win32-arm64@2.2.0: + resolution: {integrity: sha512-z225cPn3aygJsyVUOWwfyW+fY0Tvk7N3XCOl66qUPFxpbuXeZuiuuJemmtm8vxyqa3Ur7peU/qJxrpC64aeI7Q==} + engines: {node: '>= 10.0.0'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /@parcel/watcher-win32-x64@2.2.0: + resolution: {integrity: sha512-JqGW0RJ61BkKx+yYzIURt9s53P7xMVbv0uxYPzAXLBINGaFmkIKSuUPyBVfy8TMbvp93lvF4SPBNDzVRJfvgOw==} + engines: {node: '>= 10.0.0'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /@parcel/watcher@2.2.0: + resolution: {integrity: sha512-71S4TF+IMyAn24PK4KSkdKtqJDR3zRzb0HE3yXpacItqTM7XfF2f5q9NEGLEVl0dAaBAGfNwDCjH120y25F6Tg==} + engines: {node: '>= 10.0.0'} + dependencies: + detect-libc: 1.0.3 + is-glob: 4.0.3 + micromatch: 4.0.8 + node-addon-api: 7.1.1 + optionalDependencies: + '@parcel/watcher-android-arm64': 2.2.0 + '@parcel/watcher-darwin-arm64': 2.2.0 + '@parcel/watcher-darwin-x64': 2.2.0 + '@parcel/watcher-linux-arm-glibc': 2.2.0 + '@parcel/watcher-linux-arm64-glibc': 2.2.0 + '@parcel/watcher-linux-arm64-musl': 2.2.0 + '@parcel/watcher-linux-x64-glibc': 2.2.0 + '@parcel/watcher-linux-x64-musl': 2.2.0 + '@parcel/watcher-win32-arm64': 2.2.0 + '@parcel/watcher-win32-x64': 2.2.0 + dev: false + + /@parcel/workers@2.8.3(@parcel/core@2.9.3): + resolution: {integrity: sha512-+AxBnKgjqVpUHBcHLWIHcjYgKIvHIpZjN33mG5LG9XXvrZiqdWvouEzqEXlVLq5VzzVbKIQQcmsvRy138YErkg==} + engines: {node: '>= 12.0.0'} + peerDependencies: + '@parcel/core': ^2.8.3 + dependencies: + '@parcel/core': 2.9.3 + '@parcel/diagnostic': 2.8.3 + '@parcel/logger': 2.8.3 + '@parcel/types': 2.8.3(@parcel/core@2.9.3) + '@parcel/utils': 2.8.3 + chrome-trace-event: 1.0.4 + nullthrows: 1.1.1 + dev: false + + /@parcel/workers@2.9.3(@parcel/core@2.9.3): + resolution: {integrity: sha512-zRrDuZJzTevrrwElYosFztgldhqW6G9q5zOeQXfVQFkkEJCNfg36ixeiofKRU8uu2x+j+T6216mhMNB6HiuY+w==} + engines: {node: '>= 12.0.0'} + peerDependencies: + '@parcel/core': ^2.9.3 + dependencies: + '@parcel/core': 2.9.3 + '@parcel/diagnostic': 2.9.3 + '@parcel/logger': 2.9.3 + '@parcel/profiler': 2.9.3 + '@parcel/types': 2.9.3(@parcel/core@2.9.3) + '@parcel/utils': 2.9.3 + nullthrows: 1.1.1 + dev: false + + /@pkgjs/parseargs@0.11.0: + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + requiresBuild: true + optional: true + + /@plasmohq/consolidate@0.17.0(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-Na8imBnvzYPtzkK+9Uv9hPZ/oJti/0jgiQWD222SHxHw2QCVuR4KzslxXCy/rS8gGluSiTs1BGVvc3d2O6aJCA==} + engines: {node: '>= 0.10.0'} + peerDependencies: + arc-templates: ^0.5.3 + atpl: '>=0.7.6' + babel-core: ^6.26.3 + bracket-template: ^1.1.5 + coffeescript: ^2.7.0 + dot: ^1.1.3 + eco: ^1.1.0-rc-3 + ect: ^0.5.9 + ejs: ^3.1.5 + haml-coffee: ^1.14.1 + hamlet: ^0.3.3 + hamljs: ^0.6.2 + handlebars: ^4.7.6 + hogan.js: ^3.0.2 + htmling: ^0.0.8 + jazz: ^0.0.18 + jqtpl: ~1.1.0 + just: ^0.1.8 + liquid: ^5.1.1 + liquor: ^0.0.5 + lodash: ^4.17.20 + marko: ^3.14.4 + mote: ^0.2.0 + mustache: ^4.0.1 + nunjucks: ^3.2.2 + plates: ~0.4.11 + pug: ^3.0.0 + qejs: ^3.0.5 + ractive: ^1.3.12 + razor-tmpl: ^1.3.1 + react: ^18.2.0 + react-dom: ^18.2.0 + slm: ^2.0.0 + squirrelly: ^5.1.0 + teacup: ^2.0.0 + templayed: '>=0.2.3' + then-pug: '*' + tinyliquid: ^0.2.34 + toffee: ^0.3.6 + twig: ^1.15.2 + twing: ^5.0.2 + underscore: ^1.11.0 + vash: ^0.13.0 + velocityjs: ^2.0.1 + walrus: ^0.10.1 + whiskers: ^0.4.0 + peerDependenciesMeta: + arc-templates: + optional: true + atpl: + optional: true + babel-core: + optional: true + bracket-template: + optional: true + coffeescript: + optional: true + dot: + optional: true + eco: + optional: true + ect: + optional: true + ejs: + optional: true + haml-coffee: + optional: true + hamlet: + optional: true + hamljs: + optional: true + handlebars: + optional: true + hogan.js: + optional: true + htmling: + optional: true + jazz: + optional: true + jqtpl: + optional: true + just: + optional: true + liquid: + optional: true + liquor: + optional: true + lodash: + optional: true + marko: + optional: true + mote: + optional: true + mustache: + optional: true + nunjucks: + optional: true + plates: + optional: true + pug: + optional: true + qejs: + optional: true + ractive: + optional: true + razor-tmpl: + optional: true + react: + optional: true + react-dom: + optional: true + slm: + optional: true + squirrelly: + optional: true + teacup: + optional: true + templayed: + optional: true + then-pug: + optional: true + tinyliquid: + optional: true + toffee: + optional: true + twig: + optional: true + twing: + optional: true + underscore: + optional: true + vash: + optional: true + velocityjs: + optional: true + walrus: + optional: true + whiskers: + optional: true + dependencies: + bluebird: 3.7.2 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + dev: false + + /@plasmohq/init@0.7.0: + resolution: {integrity: sha512-P75g48dqOGneJ+n0AcqnLE/TYflcaPc3B7h6EopnCBBYUDnCNBMwYmKAkaf5pnhsEB0ybPS6TU1C2DTGfqaW7A==} + dev: false + + /@plasmohq/parcel-bundler@0.5.5: + resolution: {integrity: sha512-QCMmmfic514CfdXMJ7JMWUnqDzIHKVKyYeqPpUDsXON6JvA1yTmO5mEQSls8+5u/HpocP9QmTskQOHu3RCNX9A==} + engines: {node: '>= 16.0.0', parcel: '>= 2.7.0'} + dependencies: + '@parcel/core': 2.9.3 + '@parcel/diagnostic': 2.9.3 + '@parcel/graph': 2.9.3 + '@parcel/hash': 2.9.3 + '@parcel/plugin': 2.9.3(@parcel/core@2.9.3) + '@parcel/utils': 2.9.3 + nullthrows: 1.1.1 + dev: false + + /@plasmohq/parcel-compressor-utf8@0.1.0(@parcel/core@2.9.3): + resolution: {integrity: sha512-UxljXY+cUVO0ZdszoQRfQjbRjyWYIhGKCjFD48yOcnbSkOZmS5MPPhKrT79x+PMGSK5T6fUXaDjzqbnMb45MZw==} + engines: {parcel: '>= 2.8.0'} + dependencies: + '@parcel/plugin': 2.9.3(@parcel/core@2.9.3) + transitivePeerDependencies: + - '@parcel/core' + dev: false + + /@plasmohq/parcel-config@0.41.0(postcss@8.4.45)(react-dom@18.3.1)(react@18.3.1)(typescript@5.2.2): + resolution: {integrity: sha512-MHtuEyjSCqVT0J584KF4ZrnNF1KTGz3+0+wEBgYiiWEW+WW91/Hv/5pboBrPH4tu/knxSQjzE9zlY5Rq2xh9Rg==} + dependencies: + '@parcel/compressor-raw': 2.9.3(@parcel/core@2.9.3) + '@parcel/config-default': 2.9.3(@parcel/core@2.9.3)(postcss@8.4.45)(typescript@5.2.2) + '@parcel/core': 2.9.3 + '@parcel/optimizer-data-url': 2.9.3(@parcel/core@2.9.3) + '@parcel/reporter-bundle-buddy': 2.9.3(@parcel/core@2.9.3) + '@parcel/resolver-default': 2.9.3(@parcel/core@2.9.3) + '@parcel/runtime-js': 2.8.3(@parcel/core@2.9.3) + '@parcel/runtime-service-worker': 2.9.3(@parcel/core@2.9.3) + '@parcel/source-map': 2.1.1 + '@parcel/transformer-babel': 2.9.3(@parcel/core@2.9.3) + '@parcel/transformer-css': 2.9.3(@parcel/core@2.9.3) + '@parcel/transformer-graphql': 2.9.3(@parcel/core@2.9.3) + '@parcel/transformer-inline-string': 2.9.3(@parcel/core@2.9.3) + '@parcel/transformer-js': 2.9.3(@parcel/core@2.9.3) + '@parcel/transformer-less': 2.9.3(@parcel/core@2.9.3) + '@parcel/transformer-postcss': 2.9.3(@parcel/core@2.9.3) + '@parcel/transformer-raw': 2.9.3(@parcel/core@2.9.3) + '@parcel/transformer-react-refresh-wrap': 2.9.3(@parcel/core@2.9.3) + '@parcel/transformer-sass': 2.9.3(@parcel/core@2.9.3) + '@parcel/transformer-svg-react': 2.9.3(@parcel/core@2.9.3) + '@parcel/transformer-worklet': 2.9.3(@parcel/core@2.9.3) + '@plasmohq/parcel-bundler': 0.5.5 + '@plasmohq/parcel-compressor-utf8': 0.1.0(@parcel/core@2.9.3) + '@plasmohq/parcel-namer-manifest': 0.3.12 + '@plasmohq/parcel-optimizer-encapsulate': 0.0.7 + '@plasmohq/parcel-optimizer-es': 0.4.0 + '@plasmohq/parcel-packager': 0.6.14 + '@plasmohq/parcel-resolver': 0.14.0 + '@plasmohq/parcel-resolver-post': 0.4.4(postcss@8.4.45) + '@plasmohq/parcel-runtime': 0.25.0 + '@plasmohq/parcel-transformer-inject-env': 0.2.11 + '@plasmohq/parcel-transformer-inline-css': 0.3.11 + '@plasmohq/parcel-transformer-manifest': 0.19.0 + '@plasmohq/parcel-transformer-svelte': 0.6.0 + '@plasmohq/parcel-transformer-vue': 0.5.0(react-dom@18.3.1)(react@18.3.1) + transitivePeerDependencies: + - '@swc/core' + - '@swc/helpers' + - arc-templates + - atpl + - babel-core + - bracket-template + - coffeescript + - cssnano + - dot + - eco + - ect + - ejs + - haml-coffee + - hamlet + - hamljs + - handlebars + - hogan.js + - htmling + - jazz + - jqtpl + - just + - liquid + - liquor + - lodash + - marko + - mote + - mustache + - nunjucks + - plates + - postcss + - pug + - purgecss + - qejs + - ractive + - razor-tmpl + - react + - react-dom + - relateurl + - slm + - squirrelly + - srcset + - supports-color + - teacup + - templayed + - terser + - then-pug + - tinyliquid + - toffee + - ts-node + - twig + - twing + - typescript + - uncss + - underscore + - vash + - velocityjs + - walrus + - whiskers + dev: false + + /@plasmohq/parcel-core@0.1.8: + resolution: {integrity: sha512-kMWuazvf925ZAn2yHzzrb4Zsje1titFmvi/C5cXrI0TH58eT7n6GUiRXiOYP4JgGDHs/pEygx3WPuyWVTNF2HQ==} + engines: {parcel: '>= 2.7.0'} + dependencies: + '@parcel/cache': 2.9.3(@parcel/core@2.9.3) + '@parcel/core': 2.9.3 + '@parcel/diagnostic': 2.9.3 + '@parcel/events': 2.9.3 + '@parcel/fs': 2.9.3(@parcel/core@2.9.3) + '@parcel/graph': 2.9.3 + '@parcel/hash': 2.9.3 + '@parcel/logger': 2.9.3 + '@parcel/package-manager': 2.9.3(@parcel/core@2.9.3) + '@parcel/plugin': 2.9.3(@parcel/core@2.9.3) + '@parcel/source-map': 2.1.1 + '@parcel/types': 2.9.3(@parcel/core@2.9.3) + '@parcel/utils': 2.9.3 + '@parcel/watcher': 2.2.0 + '@parcel/workers': 2.9.3(@parcel/core@2.9.3) + abortcontroller-polyfill: 1.7.5 + nullthrows: 1.1.1 + dev: false + + /@plasmohq/parcel-namer-manifest@0.3.12: + resolution: {integrity: sha512-mNyIVK4nRbjlnXXUygBcmV7xLzgS1HZ3vedxUrMQah0Wp0Y20GFcomToDBC0w9NXIZVSSKY0bRIeh0B6/verfQ==} + engines: {parcel: '>= 2.7.0'} + dependencies: + '@parcel/core': 2.9.3 + '@parcel/plugin': 2.9.3(@parcel/core@2.9.3) + '@parcel/types': 2.9.3(@parcel/core@2.9.3) + '@parcel/utils': 2.9.3 + dev: false + + /@plasmohq/parcel-optimizer-encapsulate@0.0.7: + resolution: {integrity: sha512-mA9kY5dwuebQ4vLX6A5yTFo0gZZNWKUHpF6yO0lYq3oP843MyRJS8SxAtzQb4vTlVWPk3SX6Yw81DgBo4I6Xiw==} + engines: {parcel: '>= 2.8.0'} + dependencies: + '@parcel/core': 2.9.3 + '@parcel/plugin': 2.9.3(@parcel/core@2.9.3) + '@parcel/source-map': 2.1.1 + '@parcel/types': 2.9.3(@parcel/core@2.9.3) + dev: false + + /@plasmohq/parcel-optimizer-es@0.4.0: + resolution: {integrity: sha512-Iz1cTuw38wEbSQ36/dVKh5MyRA12/Ecrx90pqaIkoqA9ZSZuxuWWa7rPa3bVMFkzi28BpVHW1z9EnhVN4188kQ==} + engines: {parcel: '>= 2.8.0'} + dependencies: + '@parcel/core': 2.9.3 + '@parcel/plugin': 2.9.3(@parcel/core@2.9.3) + '@parcel/source-map': 2.1.1 + '@parcel/utils': 2.9.3 + '@swc/core': 1.3.82 + nullthrows: 1.1.1 + transitivePeerDependencies: + - '@swc/helpers' + dev: false + + /@plasmohq/parcel-packager@0.6.14: + resolution: {integrity: sha512-pFab9COfafx66CtOFWgLgKf4TUPLb5EiTO4ecRz1HDINSvPl48ci+3czmtSzOI4+b1uiqZYxUB3eeaMfh9XWpA==} + engines: {parcel: '>= 2.7.0'} + dependencies: + '@parcel/core': 2.9.3 + '@parcel/plugin': 2.9.3(@parcel/core@2.9.3) + '@parcel/types': 2.9.3(@parcel/core@2.9.3) + '@parcel/utils': 2.9.3 + nullthrows: 1.1.1 + dev: false + + /@plasmohq/parcel-resolver-post@0.4.4(postcss@8.4.45): + resolution: {integrity: sha512-n39U5z2aGAfCDFydpvEDXx0MWtqYwh0+aX4QS49/IsmZMM1Ra+GnHs/gfeJz0jtN83EytlbwSoDcXRkORx9rIQ==} + engines: {parcel: '>= 2.7.0'} + dependencies: + '@parcel/core': 2.9.3 + '@parcel/hash': 2.9.3 + '@parcel/plugin': 2.9.3(@parcel/core@2.9.3) + '@parcel/types': 2.9.3(@parcel/core@2.9.3) + '@parcel/utils': 2.9.3 + tsup: 7.2.0(postcss@8.4.45)(typescript@5.2.2) + typescript: 5.2.2 + transitivePeerDependencies: + - '@swc/core' + - postcss + - supports-color + - ts-node + dev: false + + /@plasmohq/parcel-resolver@0.14.0: + resolution: {integrity: sha512-OPGFiv2SxDEJl9sNPKfjkQ3QaqKOzSDx8E85Bq9FCOKCj+EWTPfoeUOAuMkHY/ArcvDBhWAo3Zu66f2U7iPEGQ==} + engines: {parcel: '>= 2.7.0'} + dependencies: + '@parcel/core': 2.9.3 + '@parcel/hash': 2.9.3 + '@parcel/plugin': 2.9.3(@parcel/core@2.9.3) + '@parcel/types': 2.9.3(@parcel/core@2.9.3) + fast-glob: 3.3.2 + fs-extra: 11.1.1 + got: 13.0.0 + dev: false + + /@plasmohq/parcel-runtime@0.25.0: + resolution: {integrity: sha512-jtb77WDCYhKDPi/jRweSNX9GEe/REQUQU50d18YkDpQDyo/enVTyWVeYqfo3Q21iGLX8x9E5nF2rXtIVtoOAmw==} + engines: {parcel: '>= 2.7.0'} + dependencies: + '@parcel/core': 2.9.3 + '@parcel/plugin': 2.9.3(@parcel/core@2.9.3) + '@types/trusted-types': 2.0.7 + react-refresh: 0.14.0 + dev: false + + /@plasmohq/parcel-transformer-inject-env@0.2.11: + resolution: {integrity: sha512-eGwwoaDbPPwrRcEgOi/BpLVGe5ttrBhs91NBcKMpE/D5gktfbJPD1zHG8MPtQdE4Iq23aG3JUbiT5clmdwtUhQ==} + engines: {parcel: '>= 2.7.0'} + dependencies: + '@parcel/core': 2.9.3 + '@parcel/plugin': 2.9.3(@parcel/core@2.9.3) + '@parcel/types': 2.9.3(@parcel/core@2.9.3) + dev: false + + /@plasmohq/parcel-transformer-inline-css@0.3.11: + resolution: {integrity: sha512-EUSwEowFNSgC/F1q/V4H4NXJ23wwLzlmRI6lvIr6S0mIuG/FCga+lAV3IZ+yAuXqUM2VexX6JyYYpNVidrMSxw==} + engines: {parcel: '>= 2.7.0'} + dependencies: + '@parcel/core': 2.9.3 + '@parcel/plugin': 2.9.3(@parcel/core@2.9.3) + '@parcel/utils': 2.9.3 + browserslist: 4.22.1 + lightningcss: 1.21.8 + dev: false + + /@plasmohq/parcel-transformer-manifest@0.19.0: + resolution: {integrity: sha512-cDmca0jPVFVnRQPqCWcsPPwre27/yAGxSF1+JmPVUeXZYMCrg5wdNepRDSw+/dDBO2VmNHh/Tv+Hgj1fLIM8CQ==} + engines: {parcel: '>= 2.7.0'} + dependencies: + '@mischnic/json-sourcemap': 0.1.0 + '@parcel/core': 2.9.3 + '@parcel/diagnostic': 2.9.3 + '@parcel/fs': 2.9.3(@parcel/core@2.9.3) + '@parcel/plugin': 2.9.3(@parcel/core@2.9.3) + '@parcel/types': 2.9.3(@parcel/core@2.9.3) + '@parcel/utils': 2.9.3 + content-security-policy-parser: 0.4.1 + json-schema-to-ts: 2.9.2 + nullthrows: 1.1.1 + dev: false + + /@plasmohq/parcel-transformer-svelte@0.6.0: + resolution: {integrity: sha512-5lZW6NBtzhJaCyjpKaZF1/YzY9CF+kbfNknvASJB/Cf6uJPJlrgdxoWiVJ8IWMs3DyLgAnJXTdIU+uwjwXP1wg==} + engines: {parcel: '>= 2.7.0'} + dependencies: + '@parcel/core': 2.9.3 + '@parcel/diagnostic': 2.9.3 + '@parcel/plugin': 2.9.3(@parcel/core@2.9.3) + '@parcel/source-map': 2.1.1 + '@parcel/utils': 2.9.3 + svelte: 4.2.2 + dev: false + + /@plasmohq/parcel-transformer-vue@0.5.0(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-/3oVbajt+DRqtbM0RkKFtfyZR8DVjcsYpj1jHqPParGVBiXwgP0D/8Bj5p5/5Iqihs08gzasTcjKcwQKKdj0og==} + engines: {parcel: '>= 2.7.0'} + dependencies: + '@parcel/core': 2.9.3 + '@parcel/diagnostic': 2.9.3 + '@parcel/plugin': 2.9.3(@parcel/core@2.9.3) + '@parcel/source-map': 2.1.1 + '@parcel/types': 2.9.3(@parcel/core@2.9.3) + '@parcel/utils': 2.9.3 + '@plasmohq/consolidate': 0.17.0(react-dom@18.3.1)(react@18.3.1) + '@vue/compiler-sfc': 3.3.4 + nullthrows: 1.1.1 + semver: 7.5.4 + vue: 3.3.4 + transitivePeerDependencies: + - arc-templates + - atpl + - babel-core + - bracket-template + - coffeescript + - dot + - eco + - ect + - ejs + - haml-coffee + - hamlet + - hamljs + - handlebars + - hogan.js + - htmling + - jazz + - jqtpl + - just + - liquid + - liquor + - lodash + - marko + - mote + - mustache + - nunjucks + - plates + - pug + - qejs + - ractive + - razor-tmpl + - react + - react-dom + - slm + - squirrelly + - teacup + - templayed + - then-pug + - tinyliquid + - toffee + - twig + - twing + - underscore + - vash + - velocityjs + - walrus + - whiskers + dev: false + + /@pnpm/config.env-replace@1.1.0: + resolution: {integrity: sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==} + engines: {node: '>=12.22.0'} + dev: false + + /@pnpm/network.ca-file@1.0.2: + resolution: {integrity: sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==} + engines: {node: '>=12.22.0'} + dependencies: + graceful-fs: 4.2.10 + dev: false + + /@pnpm/npm-conf@2.3.1: + resolution: {integrity: sha512-c83qWb22rNRuB0UaVCI0uRPNRr8Z0FWnEIvT47jiHAmOIUHbBOg5XvV7pM5x+rKn9HRpjxquDbXYSXr3fAKFcw==} + engines: {node: '>=12'} + dependencies: + '@pnpm/config.env-replace': 1.1.0 + '@pnpm/network.ca-file': 1.0.2 + config-chain: 1.1.13 + dev: false + + /@radix-ui/primitive@1.1.0: + resolution: {integrity: sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA==} + dev: false + + /@radix-ui/react-arrow@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-FmlW1rCg7hBpEBwFbjHwCW6AmWLQM6g/v0Sn8XbP9NvmSZ2San1FpQeyPtufzOMSIx7Y4dzjlHoifhp+7NkZhw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@types/react': 18.3.5 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + dev: false + + /@radix-ui/react-collection@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-GZsZslMJEyo1VKm5L1ZJY8tGDxZNPAoUeQUIbKeJfoi7Q4kmig5AsgLMYYuyYbfjd8fBmFORAIwYAkXMnXZgZw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-context': 1.1.0(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-slot': 1.1.0(@types/react@18.3.5)(react@18.3.1) + '@types/react': 18.3.5 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + dev: false + + /@radix-ui/react-compose-refs@1.1.0(@types/react@18.3.5)(react@18.3.1): + resolution: {integrity: sha512-b4inOtiaOnYf9KWyO3jAeeCG6FeyfY6ldiEPanbUjWd+xIk5wZeHa8yVwmrJ2vderhu/BQvzCrJI0lHd+wIiqw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 18.3.5 + react: 18.3.1 + dev: false + + /@radix-ui/react-context@1.1.0(@types/react@18.3.5)(react@18.3.1): + resolution: {integrity: sha512-OKrckBy+sMEgYM/sMmqmErVn0kZqrHPJze+Ql3DzYsDDp0hl0L62nx/2122/Bvps1qz645jlcu2tD9lrRSdf8A==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 18.3.5 + react: 18.3.1 + dev: false + + /@radix-ui/react-dialog@1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-zysS+iU4YP3STKNS6USvFVqI4qqx8EpiwmT5TuCApVEBca+eRCbONi4EgzfNSuVnOXvC5UPHHMjs8RXO6DH9Bg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/primitive': 1.1.0 + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-context': 1.1.0(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-dismissable-layer': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-focus-guards': 1.1.0(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-focus-scope': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-id': 1.1.0(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-portal': 1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-presence': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-slot': 1.1.0(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.5)(react@18.3.1) + '@types/react': 18.3.5 + '@types/react-dom': 18.3.0 + aria-hidden: 1.2.4 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + react-remove-scroll: 2.5.7(@types/react@18.3.5)(react@18.3.1) + dev: false + + /@radix-ui/react-dismissable-layer@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-/UovfmmXGptwGcBQawLzvn2jOfM0t4z3/uKffoBlj724+n3FvBbZ7M0aaBOmkp6pqFYpO4yx8tSVJjx3Fl2jig==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/primitive': 1.1.0 + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-use-escape-keydown': 1.1.0(@types/react@18.3.5)(react@18.3.1) + '@types/react': 18.3.5 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + dev: false + + /@radix-ui/react-focus-guards@1.1.0(@types/react@18.3.5)(react@18.3.1): + resolution: {integrity: sha512-w6XZNUPVv6xCpZUqb/yN9DL6auvpGX3C/ee6Hdi16v2UUy25HV2Q5bcflsiDyT/g5RwbPQ/GIT1vLkeRb+ITBw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 18.3.5 + react: 18.3.1 + dev: false + + /@radix-ui/react-focus-scope@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-200UD8zylvEyL8Bx+z76RJnASR2gRMuxlgFCPAe/Q/679a/r0eK3MBVYMb7vZODZcffZBdob1EGnky78xmVvcA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.5)(react@18.3.1) + '@types/react': 18.3.5 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + dev: false + + /@radix-ui/react-id@1.1.0(@types/react@18.3.5)(react@18.3.1): + resolution: {integrity: sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.5)(react@18.3.1) + '@types/react': 18.3.5 + react: 18.3.1 + dev: false + + /@radix-ui/react-label@2.1.0(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-peLblDlFw/ngk3UWq0VnYaOLy6agTZZ+MUO/WhVfm14vJGML+xH4FAl2XQGLqdefjNb7ApRg6Yn7U42ZhmYXdw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@types/react': 18.3.5 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + dev: false + + /@radix-ui/react-popper@1.2.0(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-ZnRMshKF43aBxVWPWvbj21+7TQCvhuULWJ4gNIKYpRlQt5xGRhLx66tMp8pya2UkGHTSlhpXwmjqltDYHhw7Vg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@floating-ui/react-dom': 2.1.1(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-arrow': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-context': 1.1.0(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-use-rect': 1.1.0(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-use-size': 1.1.0(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/rect': 1.1.0 + '@types/react': 18.3.5 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + dev: false + + /@radix-ui/react-portal@1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-A3UtLk85UtqhzFqtoC8Q0KvR2GbXF3mtPgACSazajqq6A41mEQgo53iPzY4i6BwDxlIFqWIhiQ2G729n+2aw/g==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.5)(react@18.3.1) + '@types/react': 18.3.5 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + dev: false + + /@radix-ui/react-presence@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-Gq6wuRN/asf9H/E/VzdKoUtT8GC9PQc9z40/vEr0VCJ4u5XvvhWIrSsCB6vD2/cH7ugTdSfYq9fLJCcM00acrQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.5)(react@18.3.1) + '@types/react': 18.3.5 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + dev: false + + /@radix-ui/react-primitive@2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-ZSpFm0/uHa8zTvKBDjLFWLo8dkr4MBsiDLz0g3gMUwqgLHz9rTaRRGYDgvZPtBJgYCBKXkS9fzmoySgr8CO6Cw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/react-slot': 1.1.0(@types/react@18.3.5)(react@18.3.1) + '@types/react': 18.3.5 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + dev: false + + /@radix-ui/react-slot@1.1.0(@types/react@18.3.5)(react@18.3.1): + resolution: {integrity: sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.5)(react@18.3.1) + '@types/react': 18.3.5 + react: 18.3.1 + dev: false + + /@radix-ui/react-switch@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-OBzy5WAj641k0AOSpKQtreDMe+isX0MQJ1IVyF03ucdF3DunOnROVrjWs8zsXUxC3zfZ6JL9HFVCUlMghz9dJw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/primitive': 1.1.0 + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-context': 1.1.0(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-use-previous': 1.1.0(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-use-size': 1.1.0(@types/react@18.3.5)(react@18.3.1) + '@types/react': 18.3.5 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + dev: false + + /@radix-ui/react-toast@1.2.1(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-5trl7piMXcZiCq7MW6r8YYmu0bK5qDpTWz+FdEPdKyft2UixkspheYbjbrLXVN5NGKHFbOP7lm8eD0biiSqZqg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/primitive': 1.1.0 + '@radix-ui/react-collection': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-context': 1.1.0(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-dismissable-layer': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-portal': 1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-presence': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-visually-hidden': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@types/react': 18.3.5 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + dev: false + + /@radix-ui/react-tooltip@1.1.2(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-9XRsLwe6Yb9B/tlnYCPVUd/TFS4J7HuOZW345DCeC6vKIxQGMZdx21RK4VoZauPD5frgkXTYVS5y90L+3YBn4w==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/primitive': 1.1.0 + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-context': 1.1.0(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-dismissable-layer': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-id': 1.1.0(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-popper': 1.2.0(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-portal': 1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-presence': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@radix-ui/react-slot': 1.1.0(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.5)(react@18.3.1) + '@radix-ui/react-visually-hidden': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@types/react': 18.3.5 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + dev: false + + /@radix-ui/react-use-callback-ref@1.1.0(@types/react@18.3.5)(react@18.3.1): + resolution: {integrity: sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 18.3.5 + react: 18.3.1 + dev: false + + /@radix-ui/react-use-controllable-state@1.1.0(@types/react@18.3.5)(react@18.3.1): + resolution: {integrity: sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.5)(react@18.3.1) + '@types/react': 18.3.5 + react: 18.3.1 + dev: false + + /@radix-ui/react-use-escape-keydown@1.1.0(@types/react@18.3.5)(react@18.3.1): + resolution: {integrity: sha512-L7vwWlR1kTTQ3oh7g1O0CBF3YCyyTj8NmhLR+phShpyA50HCfBFKVJTpshm9PzLiKmehsrQzTYTpX9HvmC9rhw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.5)(react@18.3.1) + '@types/react': 18.3.5 + react: 18.3.1 + dev: false + + /@radix-ui/react-use-layout-effect@1.1.0(@types/react@18.3.5)(react@18.3.1): + resolution: {integrity: sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 18.3.5 + react: 18.3.1 + dev: false + + /@radix-ui/react-use-previous@1.1.0(@types/react@18.3.5)(react@18.3.1): + resolution: {integrity: sha512-Z/e78qg2YFnnXcW88A4JmTtm4ADckLno6F7OXotmkQfeuCVaKuYzqAATPhVzl3delXE7CxIV8shofPn3jPc5Og==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 18.3.5 + react: 18.3.1 + dev: false + + /@radix-ui/react-use-rect@1.1.0(@types/react@18.3.5)(react@18.3.1): + resolution: {integrity: sha512-0Fmkebhr6PiseyZlYAOtLS+nb7jLmpqTrJyv61Pe68MKYW6OWdRE2kI70TaYY27u7H0lajqM3hSMMLFq18Z7nQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@radix-ui/rect': 1.1.0 + '@types/react': 18.3.5 + react: 18.3.1 + dev: false + + /@radix-ui/react-use-size@1.1.0(@types/react@18.3.5)(react@18.3.1): + resolution: {integrity: sha512-XW3/vWuIXHa+2Uwcc2ABSfcCledmXhhQPlGbfcRXbiUQI5Icjcg19BGCZVKKInYbvUCut/ufbbLLPFC5cbb1hw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.5)(react@18.3.1) + '@types/react': 18.3.5 + react: 18.3.1 + dev: false + + /@radix-ui/react-visually-hidden@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-N8MDZqtgCgG5S3aV60INAB475osJousYpZ4cTJ2cFbMpdHS5Y6loLTH8LPtkj2QN0x93J30HT/M3qJXM0+lyeQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.5)(react-dom@18.3.1)(react@18.3.1) + '@types/react': 18.3.5 + '@types/react-dom': 18.3.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + dev: false + + /@radix-ui/rect@1.1.0: + resolution: {integrity: sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==} + dev: false + + /@rollup/rollup-android-arm-eabi@4.21.2: + resolution: {integrity: sha512-fSuPrt0ZO8uXeS+xP3b+yYTCBUd05MoSp2N/MFOgjhhUhMmchXlpTQrTpI8T+YAwAQuK7MafsCOxW7VrPMrJcg==} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-android-arm64@4.21.2: + resolution: {integrity: sha512-xGU5ZQmPlsjQS6tzTTGwMsnKUtu0WVbl0hYpTPauvbRAnmIvpInhJtgjj3mcuJpEiuUw4v1s4BimkdfDWlh7gA==} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-darwin-arm64@4.21.2: + resolution: {integrity: sha512-99AhQ3/ZMxU7jw34Sq8brzXqWH/bMnf7ZVhvLk9QU2cOepbQSVTns6qoErJmSiAvU3InRqC2RRZ5ovh1KN0d0Q==} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-darwin-x64@4.21.2: + resolution: {integrity: sha512-ZbRaUvw2iN/y37x6dY50D8m2BnDbBjlnMPotDi/qITMJ4sIxNY33HArjikDyakhSv0+ybdUxhWxE6kTI4oX26w==} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-arm-gnueabihf@4.21.2: + resolution: {integrity: sha512-ztRJJMiE8nnU1YFcdbd9BcH6bGWG1z+jP+IPW2oDUAPxPjo9dverIOyXz76m6IPA6udEL12reYeLojzW2cYL7w==} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-arm-musleabihf@4.21.2: + resolution: {integrity: sha512-flOcGHDZajGKYpLV0JNc0VFH361M7rnV1ee+NTeC/BQQ1/0pllYcFmxpagltANYt8FYf9+kL6RSk80Ziwyhr7w==} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-arm64-gnu@4.21.2: + resolution: {integrity: sha512-69CF19Kp3TdMopyteO/LJbWufOzqqXzkrv4L2sP8kfMaAQ6iwky7NoXTp7bD6/irKgknDKM0P9E/1l5XxVQAhw==} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-arm64-musl@4.21.2: + resolution: {integrity: sha512-48pD/fJkTiHAZTnZwR0VzHrao70/4MlzJrq0ZsILjLW/Ab/1XlVUStYyGt7tdyIiVSlGZbnliqmult/QGA2O2w==} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-powerpc64le-gnu@4.21.2: + resolution: {integrity: sha512-cZdyuInj0ofc7mAQpKcPR2a2iu4YM4FQfuUzCVA2u4HI95lCwzjoPtdWjdpDKyHxI0UO82bLDoOaLfpZ/wviyQ==} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-riscv64-gnu@4.21.2: + resolution: {integrity: sha512-RL56JMT6NwQ0lXIQmMIWr1SW28z4E4pOhRRNqwWZeXpRlykRIlEpSWdsgNWJbYBEWD84eocjSGDu/XxbYeCmwg==} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-s390x-gnu@4.21.2: + resolution: {integrity: sha512-PMxkrWS9z38bCr3rWvDFVGD6sFeZJw4iQlhrup7ReGmfn7Oukrr/zweLhYX6v2/8J6Cep9IEA/SmjXjCmSbrMQ==} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-x64-gnu@4.21.2: + resolution: {integrity: sha512-B90tYAUoLhU22olrafY3JQCFLnT3NglazdwkHyxNDYF/zAxJt5fJUB/yBoWFoIQ7SQj+KLe3iL4BhOMa9fzgpw==} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-linux-x64-musl@4.21.2: + resolution: {integrity: sha512-7twFizNXudESmC9oneLGIUmoHiiLppz/Xs5uJQ4ShvE6234K0VB1/aJYU3f/4g7PhssLGKBVCC37uRkkOi8wjg==} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-win32-arm64-msvc@4.21.2: + resolution: {integrity: sha512-9rRero0E7qTeYf6+rFh3AErTNU1VCQg2mn7CQcI44vNUWM9Ze7MSRS/9RFuSsox+vstRt97+x3sOhEey024FRQ==} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-win32-ia32-msvc@4.21.2: + resolution: {integrity: sha512-5rA4vjlqgrpbFVVHX3qkrCo/fZTj1q0Xxpg+Z7yIo3J2AilW7t2+n6Q8Jrx+4MrYpAnjttTYF8rr7bP46BPzRw==} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@rollup/rollup-win32-x64-msvc@4.21.2: + resolution: {integrity: sha512-6UUxd0+SKomjdzuAcp+HAmxw1FlGBnl1v2yEPSabtx4lBfdXHDVsW7+lQkgz9cNFJGY3AWR7+V8P5BqkD9L9nA==} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@rtsao/scc@1.1.0: + resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} + dev: false + + /@scure/base@1.1.8: + resolution: {integrity: sha512-6CyAclxj3Nb0XT7GHK6K4zK6k2xJm6E4Ft0Ohjt4WgegiFUHEtFb2CGzmPmGBwoIhrLsqNLYfLr04Y1GePrzZg==} + dev: false + + /@scure/bip32@1.4.0: + resolution: {integrity: sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg==} + dependencies: + '@noble/curves': 1.4.0 + '@noble/hashes': 1.4.0 + '@scure/base': 1.1.8 + dev: false + + /@scure/bip39@1.3.0: + resolution: {integrity: sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ==} + dependencies: + '@noble/hashes': 1.4.0 + '@scure/base': 1.1.8 + dev: false + + /@sindresorhus/is@5.6.0: + resolution: {integrity: sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==} + engines: {node: '>=14.16'} + dev: false + + /@svgr/babel-plugin-add-jsx-attribute@6.5.1(@babel/core@7.25.2): + resolution: {integrity: sha512-9PYGcXrAxitycIjRmZB+Q0JaN07GZIWaTBIGQzfaZv+qr1n8X1XUEJ5rZ/vx6OVD9RRYlrNnXWExQXcmZeD/BQ==} + engines: {node: '>=10'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + dev: false + + /@svgr/babel-plugin-remove-jsx-attribute@8.0.0(@babel/core@7.25.2): + resolution: {integrity: sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA==} + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + dev: false + + /@svgr/babel-plugin-remove-jsx-empty-expression@8.0.0(@babel/core@7.25.2): + resolution: {integrity: sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA==} + engines: {node: '>=14'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + dev: false + + /@svgr/babel-plugin-replace-jsx-attribute-value@6.5.1(@babel/core@7.25.2): + resolution: {integrity: sha512-8DPaVVE3fd5JKuIC29dqyMB54sA6mfgki2H2+swh+zNJoynC8pMPzOkidqHOSc6Wj032fhl8Z0TVn1GiPpAiJg==} + engines: {node: '>=10'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + dev: false + + /@svgr/babel-plugin-svg-dynamic-title@6.5.1(@babel/core@7.25.2): + resolution: {integrity: sha512-FwOEi0Il72iAzlkaHrlemVurgSQRDFbk0OC8dSvD5fSBPHltNh7JtLsxmZUhjYBZo2PpcU/RJvvi6Q0l7O7ogw==} + engines: {node: '>=10'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + dev: false + + /@svgr/babel-plugin-svg-em-dimensions@6.5.1(@babel/core@7.25.2): + resolution: {integrity: sha512-gWGsiwjb4tw+ITOJ86ndY/DZZ6cuXMNE/SjcDRg+HLuCmwpcjOktwRF9WgAiycTqJD/QXqL2f8IzE2Rzh7aVXA==} + engines: {node: '>=10'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + dev: false + + /@svgr/babel-plugin-transform-react-native-svg@6.5.1(@babel/core@7.25.2): + resolution: {integrity: sha512-2jT3nTayyYP7kI6aGutkyfJ7UMGtuguD72OjeGLwVNyfPRBD8zQthlvL+fAbAKk5n9ZNcvFkp/b1lZ7VsYqVJg==} + engines: {node: '>=10'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + dev: false + + /@svgr/babel-plugin-transform-svg-component@6.5.1(@babel/core@7.25.2): + resolution: {integrity: sha512-a1p6LF5Jt33O3rZoVRBqdxL350oge54iZWHNI6LJB5tQ7EelvD/Mb1mfBiZNAan0dt4i3VArkFRjA4iObuNykQ==} + engines: {node: '>=12'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + dev: false + + /@svgr/babel-preset@6.5.1(@babel/core@7.25.2): + resolution: {integrity: sha512-6127fvO/FF2oi5EzSQOAjo1LE3OtNVh11R+/8FXa+mHx1ptAaS4cknIjnUA7e6j6fwGGJ17NzaTJFUwOV2zwCw==} + engines: {node: '>=10'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.25.2 + '@svgr/babel-plugin-add-jsx-attribute': 6.5.1(@babel/core@7.25.2) + '@svgr/babel-plugin-remove-jsx-attribute': 8.0.0(@babel/core@7.25.2) + '@svgr/babel-plugin-remove-jsx-empty-expression': 8.0.0(@babel/core@7.25.2) + '@svgr/babel-plugin-replace-jsx-attribute-value': 6.5.1(@babel/core@7.25.2) + '@svgr/babel-plugin-svg-dynamic-title': 6.5.1(@babel/core@7.25.2) + '@svgr/babel-plugin-svg-em-dimensions': 6.5.1(@babel/core@7.25.2) + '@svgr/babel-plugin-transform-react-native-svg': 6.5.1(@babel/core@7.25.2) + '@svgr/babel-plugin-transform-svg-component': 6.5.1(@babel/core@7.25.2) + dev: false + + /@svgr/core@6.5.1: + resolution: {integrity: sha512-/xdLSWxK5QkqG524ONSjvg3V/FkNyCv538OIBdQqPNaAta3AsXj/Bd2FbvR87yMbXO2hFSWiAe/Q6IkVPDw+mw==} + engines: {node: '>=10'} + dependencies: + '@babel/core': 7.25.2 + '@svgr/babel-preset': 6.5.1(@babel/core@7.25.2) + '@svgr/plugin-jsx': 6.5.1(@svgr/core@6.5.1) + camelcase: 6.3.0 + cosmiconfig: 7.1.0 + transitivePeerDependencies: + - supports-color + dev: false + + /@svgr/hast-util-to-babel-ast@6.5.1: + resolution: {integrity: sha512-1hnUxxjd83EAxbL4a0JDJoD3Dao3hmjvyvyEV8PzWmLK3B9m9NPlW7GKjFyoWE8nM7HnXzPcmmSyOW8yOddSXw==} + engines: {node: '>=10'} + dependencies: + '@babel/types': 7.25.6 + entities: 4.5.0 + dev: false + + /@svgr/plugin-jsx@6.5.1(@svgr/core@6.5.1): + resolution: {integrity: sha512-+UdQxI3jgtSjCykNSlEMuy1jSRQlGC7pqBCPvkG/2dATdWo082zHTTK3uhnAju2/6XpE6B5mZ3z4Z8Ns01S8Gw==} + engines: {node: '>=10'} + peerDependencies: + '@svgr/core': ^6.0.0 + dependencies: + '@babel/core': 7.25.2 + '@svgr/babel-preset': 6.5.1(@babel/core@7.25.2) + '@svgr/core': 6.5.1 + '@svgr/hast-util-to-babel-ast': 6.5.1 + svg-parser: 2.0.4 + transitivePeerDependencies: + - supports-color + dev: false + + /@svgr/plugin-svgo@6.5.1(@svgr/core@6.5.1): + resolution: {integrity: sha512-omvZKf8ixP9z6GWgwbtmP9qQMPX4ODXi+wzbVZgomNFsUIlHA1sf4fThdwTWSsZGgvGAG6yE+b/F5gWUkcZ/iQ==} + engines: {node: '>=10'} + peerDependencies: + '@svgr/core': '*' + dependencies: + '@svgr/core': 6.5.1 + cosmiconfig: 7.1.0 + deepmerge: 4.3.1 + svgo: 2.8.0 + dev: false + + /@swc/core-darwin-arm64@1.3.82: + resolution: {integrity: sha512-JfsyDW34gVKD3uE0OUpUqYvAD3yseEaicnFP6pB292THtLJb0IKBBnK50vV/RzEJtc1bR3g1kNfxo2PeurZTrA==} + engines: {node: '>=10'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /@swc/core-darwin-arm64@1.7.23: + resolution: {integrity: sha512-yyOHPfti6yKlQulfVWMt7BVKst+SyEZYCWuQSGMn1KgmNCH/bYufRWfQXIhkGSj44ZkEepJmsJ8tDyIb4k5WyA==} + engines: {node: '>=10'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /@swc/core-darwin-x64@1.3.82: + resolution: {integrity: sha512-ogQWgNMq7qTpITjcP3dnzkFNj7bh6SwMr859GvtOTrE75H7L7jDWxESfH4f8foB/LGxBKiDNmxKhitCuAsZK4A==} + engines: {node: '>=10'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /@swc/core-darwin-x64@1.7.23: + resolution: {integrity: sha512-GzqHwQ0Y1VyjdI/bBKFX2GKm5HD3PIB6OhuAQtWZMTtEr2yIrlT0YK2T+XKh7oIg31JwxGBeQdBk3KTI7DARmQ==} + engines: {node: '>=10'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /@swc/core-linux-arm-gnueabihf@1.3.82: + resolution: {integrity: sha512-7TMXG1lXlNhD0kUiEqs+YlGV4irAdBa2quuy+XI3oJf2fBK6dQfEq4xBy65B3khrorzQS3O0oDGQ+cmdpHExHA==} + engines: {node: '>=10'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@swc/core-linux-arm-gnueabihf@1.7.23: + resolution: {integrity: sha512-qwX4gB41OS6/OZkHcpTqLFGsdmvoZyffnJIlgB/kZKwH3lfeJWzv6vx57zXtNpM/t7GoQEe0VZUVdmNjxSxBZw==} + engines: {node: '>=10'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@swc/core-linux-arm64-gnu@1.3.82: + resolution: {integrity: sha512-26JkOujbzcItPAmIbD5vHJxQVy5ihcSu3YHTKwope1h28sApZdtE7S3e2G3gsZRTIdsCQkXUtAQeqHxGWWR3pw==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@swc/core-linux-arm64-gnu@1.7.23: + resolution: {integrity: sha512-TsrbUZdMaUwzI7+g/8rHPLWbntMKYSu5Bn5IBSqVKPeyqaXxNnlIUnWXgXcUcRAc+T+Y8ADfr7EiFz9iz5DuSA==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@swc/core-linux-arm64-musl@1.3.82: + resolution: {integrity: sha512-8Izj9tuuMpoc3cqiPBRtwqpO1BZ/+sfZVsEhLxrbOFlcSb8LnKyMle1g3JMMUwI4EU75RGVIzZMn8A6GOKdJbA==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@swc/core-linux-arm64-musl@1.7.23: + resolution: {integrity: sha512-JEdtwdthazKq4PBz53KSubwwK8MvqODAihGSAzc8u3Unq4ojcvaS8b0CwLBeD+kTQ78HpxOXTt3DsFIxpgaCAA==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@swc/core-linux-x64-gnu@1.3.82: + resolution: {integrity: sha512-0GSrIBScQwTaPv46T2qB7XnDYxndRCpwH4HMjh6FN+I+lfPUhTSJKW8AonqrqT1TbpFIgvzQs7EnTsD7AnSCow==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@swc/core-linux-x64-gnu@1.7.23: + resolution: {integrity: sha512-V51gFPWaVAHbI1yg9ahsoya3aB4uawye3SZ5uQWgcP7wdCdiv60dw4F5nuPJf5Z1oXD3U/BslXuamv8Oh9vXqQ==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@swc/core-linux-x64-musl@1.3.82: + resolution: {integrity: sha512-KJUnaaepDKNzrEbwz4jv0iC3/t9x0NSoe06fnkAlhh2+NFKWKKJhVCOBTrpds8n7eylBDIXUlK34XQafjVMUdg==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@swc/core-linux-x64-musl@1.7.23: + resolution: {integrity: sha512-BBqQi4+UdeRqag3yM4IJjaHG4yc1o3l9ksENHToE0o/u2DT0FY5+K/DiYGZLC1JHbSFzNqRCYsa7DIzRtZ0A1A==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@swc/core-win32-arm64-msvc@1.3.82: + resolution: {integrity: sha512-TR3MHKhDYIyGyFcyl2d/p1ftceXcubAhX5wRSOdtOyr5+K/v3jbyCCqN7bbqO5o43wQVCwwR/drHleYyDZvg8Q==} + engines: {node: '>=10'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /@swc/core-win32-arm64-msvc@1.7.23: + resolution: {integrity: sha512-JPk6pvCKncL6bXG7p+NLZf8PWx4FakVvKNdwGeMrYunb+yk1IZf7qf9LJk8+GDGF5QviDXPs8opZrTrfsW80fA==} + engines: {node: '>=10'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /@swc/core-win32-ia32-msvc@1.3.82: + resolution: {integrity: sha512-ZX4HzVVt6hs84YUg70UvyBJnBOIspmQQM0iXSzBvOikk3zRoN7BnDwQH4GScvevCEBuou60+i4I6d5kHLOfh8Q==} + engines: {node: '>=10'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /@swc/core-win32-ia32-msvc@1.7.23: + resolution: {integrity: sha512-2Whxi8d+bLQBzJcQ5qYPHlk02YYVGsMVav0fWk+FnX2z1QRREIu1L1xvrpi7gBpjXp6BIU40ya8GiKeekNT2bg==} + engines: {node: '>=10'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /@swc/core-win32-x64-msvc@1.3.82: + resolution: {integrity: sha512-4mJMnex21kbQoaHeAmHnVwQN9/XAfPszJ6n9HI7SVH+aAHnbBIR0M59/b50/CJMjTj5niUGk7EwQ3nhVNOG32g==} + engines: {node: '>=10'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /@swc/core-win32-x64-msvc@1.7.23: + resolution: {integrity: sha512-82fARk4/yJ40kwWKY/gdKDisPdtgJE9jgpl/vkNG3alyJxrCzuNM7+CtiKoYbXLeqM8GQTS3wlvCaJu9oQ8dag==} + engines: {node: '>=10'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /@swc/core@1.3.82: + resolution: {integrity: sha512-jpC1a18HMH67018Ij2jh+hT7JBFu7ZKcQVfrZ8K6JuEY+kjXmbea07P9MbQUZbAe0FB+xi3CqEVCP73MebodJQ==} + engines: {node: '>=10'} + requiresBuild: true + peerDependencies: + '@swc/helpers': ^0.5.0 + peerDependenciesMeta: + '@swc/helpers': + optional: true + dependencies: + '@swc/types': 0.1.12 + optionalDependencies: + '@swc/core-darwin-arm64': 1.3.82 + '@swc/core-darwin-x64': 1.3.82 + '@swc/core-linux-arm-gnueabihf': 1.3.82 + '@swc/core-linux-arm64-gnu': 1.3.82 + '@swc/core-linux-arm64-musl': 1.3.82 + '@swc/core-linux-x64-gnu': 1.3.82 + '@swc/core-linux-x64-musl': 1.3.82 + '@swc/core-win32-arm64-msvc': 1.3.82 + '@swc/core-win32-ia32-msvc': 1.3.82 + '@swc/core-win32-x64-msvc': 1.3.82 + dev: false + + /@swc/core@1.7.23: + resolution: {integrity: sha512-VDNkpDvDlreGh2E3tlDj8B3piiuLhhQA/7rIVZpiLUvG1YpucAa6N7iDXA7Gc/+Hah8spaCg/qvEaBkCmcIYCQ==} + engines: {node: '>=10'} + requiresBuild: true + peerDependencies: + '@swc/helpers': '*' + peerDependenciesMeta: + '@swc/helpers': + optional: true + dependencies: + '@swc/counter': 0.1.3 + '@swc/types': 0.1.12 + optionalDependencies: + '@swc/core-darwin-arm64': 1.7.23 + '@swc/core-darwin-x64': 1.7.23 + '@swc/core-linux-arm-gnueabihf': 1.7.23 + '@swc/core-linux-arm64-gnu': 1.7.23 + '@swc/core-linux-arm64-musl': 1.7.23 + '@swc/core-linux-x64-gnu': 1.7.23 + '@swc/core-linux-x64-musl': 1.7.23 + '@swc/core-win32-arm64-msvc': 1.7.23 + '@swc/core-win32-ia32-msvc': 1.7.23 + '@swc/core-win32-x64-msvc': 1.7.23 + dev: false + + /@swc/counter@0.1.3: + resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} + dev: false + + /@swc/helpers@0.5.13: + resolution: {integrity: sha512-UoKGxQ3r5kYI9dALKJapMmuK+1zWM/H17Z1+iwnNmzcJRnfFuevZs375TA5rW31pu4BS4NoSy1fRsexDXfWn5w==} + dependencies: + tslib: 2.7.0 + dev: false + + /@swc/types@0.1.12: + resolution: {integrity: sha512-wBJA+SdtkbFhHjTMYH+dEH1y4VpfGdAc2Kw/LK09i9bXd/K6j6PkDcFCEzb6iVfZMkPRrl/q0e3toqTAJdkIVA==} + dependencies: + '@swc/counter': 0.1.3 + dev: false + + /@szmarczak/http-timer@5.0.1: + resolution: {integrity: sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==} + engines: {node: '>=14.16'} + dependencies: + defer-to-connect: 2.0.1 + dev: false + + /@tanstack/eslint-plugin-query@5.53.0(eslint@8.57.0)(typescript@5.5.4): + resolution: {integrity: sha512-Q3WgvK2YTGc3h5EaktDouRkKBPGl3QQFLPZBagpBa6zD70PiNoDY72wWrX9T4yKClMmSulAa0wg5Nj3LVXGkEw==} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + dependencies: + '@typescript-eslint/utils': 8.4.0(eslint@8.57.0)(typescript@5.5.4) + eslint: 8.57.0 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + /@tanstack/query-core@5.56.2: + resolution: {integrity: sha512-gor0RI3/R5rVV3gXfddh1MM+hgl0Z4G7tj6Xxpq6p2I03NGPaJ8dITY9Gz05zYYb/EJq9vPas/T4wn9EaDPd4Q==} + dev: false + + /@tanstack/react-query@5.56.2(react@18.3.1): + resolution: {integrity: sha512-SR0GzHVo6yzhN72pnRhkEFRAHMsUo5ZPzAxfTMvUxFIDVS6W9LYUp6nXW3fcHVdg0ZJl8opSH85jqahvm6DSVg==} + peerDependencies: + react: ^18 || ^19 + dependencies: + '@tanstack/query-core': 5.56.2 + react: 18.3.1 + dev: false + + /@trysound/sax@0.2.0: + resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==} + engines: {node: '>=10.13.0'} + dev: false + + /@types/babel__core@7.20.5: + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + dependencies: + '@babel/parser': 7.25.6 + '@babel/types': 7.25.6 + '@types/babel__generator': 7.6.8 + '@types/babel__template': 7.4.4 + '@types/babel__traverse': 7.20.6 + dev: true + + /@types/babel__generator@7.6.8: + resolution: {integrity: sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==} + dependencies: + '@babel/types': 7.25.6 + dev: true + + /@types/babel__template@7.4.4: + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + dependencies: + '@babel/parser': 7.25.6 + '@babel/types': 7.25.6 + dev: true + + /@types/babel__traverse@7.20.6: + resolution: {integrity: sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==} + dependencies: + '@babel/types': 7.25.6 + dev: true + + /@types/chrome@0.0.268: + resolution: {integrity: sha512-7N1QH9buudSJ7sI8Pe4mBHJr5oZ48s0hcanI9w3wgijAlv1OZNUZve9JR4x42dn5lJ5Sm87V1JNfnoh10EnQlA==} + dependencies: + '@types/filesystem': 0.0.36 + '@types/har-format': 1.2.15 + dev: true + + /@types/estree@1.0.5: + resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} + + /@types/filesystem@0.0.36: + resolution: {integrity: sha512-vPDXOZuannb9FZdxgHnqSwAG/jvdGM8Wq+6N4D/d80z+D4HWH+bItqsZaVRQykAn6WEVeEkLm2oQigyHtgb0RA==} + dependencies: + '@types/filewriter': 0.0.33 + dev: true + + /@types/filewriter@0.0.33: + resolution: {integrity: sha512-xFU8ZXTw4gd358lb2jw25nxY9QAgqn2+bKKjKOYfNCzN4DKCFetK7sPtrlpg66Ywe3vWY9FNxprZawAh9wfJ3g==} + dev: true + + /@types/har-format@1.2.15: + resolution: {integrity: sha512-RpQH4rXLuvTXKR0zqHq3go0RVXYv/YVqv4TnPH95VbwUxZdQlK1EtcMvQvMpDngHbt13Csh9Z4qT9AbkiQH5BA==} + dev: true + + /@types/http-cache-semantics@4.0.4: + resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==} + dev: false + + /@types/json-schema@7.0.15: + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + dev: false + + /@types/json5@0.0.29: + resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} + dev: false + + /@types/node@20.16.4: + resolution: {integrity: sha512-ioyQ1zK9aGEomJ45zz8S8IdzElyxhvP1RVWnPrXDf6wFaUb+kk1tEcVVJkF7RPGM0VWI7cp5U57oCPIn5iN1qg==} + dependencies: + undici-types: 6.19.8 + dev: true + + /@types/parse-json@4.0.2: + resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} + dev: false + + /@types/prop-types@15.7.12: + resolution: {integrity: sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==} + + /@types/react-dom@18.3.0: + resolution: {integrity: sha512-EhwApuTmMBmXuFOikhQLIBUn6uFg81SwLMOAUgodJF14SOBOCMdU04gDoYi0WOJJHD144TL32z4yDqCW3dnkQg==} + dependencies: + '@types/react': 18.3.5 + + /@types/react@18.3.5: + resolution: {integrity: sha512-WeqMfGJLGuLCqHGYRGHxnKrXcTitc6L/nBUWfWPcTarG3t9PsquqUMuVeXZeca+mglY4Vo5GZjCi0A3Or2lnxA==} + dependencies: + '@types/prop-types': 15.7.12 + csstype: 3.1.3 + + /@types/trusted-types@2.0.7: + resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} + dev: false + + /@typescript-eslint/eslint-plugin@7.18.0(@typescript-eslint/parser@7.18.0)(eslint@8.57.0)(typescript@5.5.4): + resolution: {integrity: sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw==} + engines: {node: ^18.18.0 || >=20.0.0} + peerDependencies: + '@typescript-eslint/parser': ^7.0.0 + eslint: ^8.56.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@eslint-community/regexpp': 4.11.0 + '@typescript-eslint/parser': 7.18.0(eslint@8.57.0)(typescript@5.5.4) + '@typescript-eslint/scope-manager': 7.18.0 + '@typescript-eslint/type-utils': 7.18.0(eslint@8.57.0)(typescript@5.5.4) + '@typescript-eslint/utils': 7.18.0(eslint@8.57.0)(typescript@5.5.4) + '@typescript-eslint/visitor-keys': 7.18.0 + eslint: 8.57.0 + graphemer: 1.4.0 + ignore: 5.3.2 + natural-compare: 1.4.0 + ts-api-utils: 1.3.0(typescript@5.5.4) + typescript: 5.5.4 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/parser@7.18.0(eslint@8.57.0)(typescript@5.5.4): + resolution: {integrity: sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==} + engines: {node: ^18.18.0 || >=20.0.0} + peerDependencies: + eslint: ^8.56.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/scope-manager': 7.18.0 + '@typescript-eslint/types': 7.18.0 + '@typescript-eslint/typescript-estree': 7.18.0(typescript@5.5.4) + '@typescript-eslint/visitor-keys': 7.18.0 + debug: 4.3.6 + eslint: 8.57.0 + typescript: 5.5.4 + transitivePeerDependencies: + - supports-color + + /@typescript-eslint/scope-manager@7.18.0: + resolution: {integrity: sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==} + engines: {node: ^18.18.0 || >=20.0.0} + dependencies: + '@typescript-eslint/types': 7.18.0 + '@typescript-eslint/visitor-keys': 7.18.0 + + /@typescript-eslint/scope-manager@8.4.0: + resolution: {integrity: sha512-n2jFxLeY0JmKfUqy3P70rs6vdoPjHK8P/w+zJcV3fk0b0BwRXC/zxRTEnAsgYT7MwdQDt/ZEbtdzdVC+hcpF0A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + '@typescript-eslint/types': 8.4.0 + '@typescript-eslint/visitor-keys': 8.4.0 + dev: true + + /@typescript-eslint/type-utils@7.18.0(eslint@8.57.0)(typescript@5.5.4): + resolution: {integrity: sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA==} + engines: {node: ^18.18.0 || >=20.0.0} + peerDependencies: + eslint: ^8.56.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/typescript-estree': 7.18.0(typescript@5.5.4) + '@typescript-eslint/utils': 7.18.0(eslint@8.57.0)(typescript@5.5.4) + debug: 4.3.6 + eslint: 8.57.0 + ts-api-utils: 1.3.0(typescript@5.5.4) + typescript: 5.5.4 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/types@7.18.0: + resolution: {integrity: sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==} + engines: {node: ^18.18.0 || >=20.0.0} + + /@typescript-eslint/types@8.4.0: + resolution: {integrity: sha512-T1RB3KQdskh9t3v/qv7niK6P8yvn7ja1mS7QK7XfRVL6wtZ8/mFs/FHf4fKvTA0rKnqnYxl/uHFNbnEt0phgbw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dev: true + + /@typescript-eslint/typescript-estree@7.18.0(typescript@5.5.4): + resolution: {integrity: sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==} + engines: {node: ^18.18.0 || >=20.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/types': 7.18.0 + '@typescript-eslint/visitor-keys': 7.18.0 + debug: 4.3.6 + globby: 11.1.0 + is-glob: 4.0.3 + minimatch: 9.0.5 + semver: 7.6.3 + ts-api-utils: 1.3.0(typescript@5.5.4) + typescript: 5.5.4 + transitivePeerDependencies: + - supports-color + + /@typescript-eslint/typescript-estree@8.4.0(typescript@5.5.4): + resolution: {integrity: sha512-kJ2OIP4dQw5gdI4uXsaxUZHRwWAGpREJ9Zq6D5L0BweyOrWsL6Sz0YcAZGWhvKnH7fm1J5YFE1JrQL0c9dd53A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/types': 8.4.0 + '@typescript-eslint/visitor-keys': 8.4.0 + debug: 4.3.6 + fast-glob: 3.3.2 + is-glob: 4.0.3 + minimatch: 9.0.5 + semver: 7.6.3 + ts-api-utils: 1.3.0(typescript@5.5.4) + typescript: 5.5.4 + transitivePeerDependencies: + - supports-color + dev: true + + /@typescript-eslint/utils@7.18.0(eslint@8.57.0)(typescript@5.5.4): + resolution: {integrity: sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==} + engines: {node: ^18.18.0 || >=20.0.0} + peerDependencies: + eslint: ^8.56.0 + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) + '@typescript-eslint/scope-manager': 7.18.0 + '@typescript-eslint/types': 7.18.0 + '@typescript-eslint/typescript-estree': 7.18.0(typescript@5.5.4) + eslint: 8.57.0 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + /@typescript-eslint/utils@8.4.0(eslint@8.57.0)(typescript@5.5.4): + resolution: {integrity: sha512-swULW8n1IKLjRAgciCkTCafyTHHfwVQFt8DovmaF69sKbOxTSFMmIZaSHjqO9i/RV0wIblaawhzvtva8Nmm7lQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) + '@typescript-eslint/scope-manager': 8.4.0 + '@typescript-eslint/types': 8.4.0 + '@typescript-eslint/typescript-estree': 8.4.0(typescript@5.5.4) + eslint: 8.57.0 + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + /@typescript-eslint/visitor-keys@7.18.0: + resolution: {integrity: sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==} + engines: {node: ^18.18.0 || >=20.0.0} + dependencies: + '@typescript-eslint/types': 7.18.0 + eslint-visitor-keys: 3.4.3 + + /@typescript-eslint/visitor-keys@8.4.0: + resolution: {integrity: sha512-zTQD6WLNTre1hj5wp09nBIDiOc2U5r/qmzo7wxPn4ZgAjHql09EofqhF9WF+fZHzL5aCyaIpPcT2hyxl73kr9A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + dependencies: + '@typescript-eslint/types': 8.4.0 + eslint-visitor-keys: 3.4.3 + dev: true + + /@ungap/structured-clone@1.2.0: + resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} + + /@vitejs/plugin-react@4.3.1(vite@5.4.3): + resolution: {integrity: sha512-m/V2syj5CuVnaxcUJOQRel/Wr31FFXRFlnOoq1TVtkCxsY5veGMTEmpWHndrhB2U8ScHtCQB1e+4hWYExQc6Lg==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + vite: ^4.2.0 || ^5.0.0 + dependencies: + '@babel/core': 7.25.2 + '@babel/plugin-transform-react-jsx-self': 7.24.7(@babel/core@7.25.2) + '@babel/plugin-transform-react-jsx-source': 7.24.7(@babel/core@7.25.2) + '@types/babel__core': 7.20.5 + react-refresh: 0.14.2 + vite: 5.4.3(@types/node@20.16.4) + transitivePeerDependencies: + - supports-color + dev: true + + /@vue/compiler-core@3.3.4: + resolution: {integrity: sha512-cquyDNvZ6jTbf/+x+AgM2Arrp6G4Dzbb0R64jiG804HRMfRiFXWI6kqUVqZ6ZR0bQhIoQjB4+2bhNtVwndW15g==} + dependencies: + '@babel/parser': 7.25.6 + '@vue/shared': 3.3.4 + estree-walker: 2.0.2 + source-map-js: 1.2.0 + dev: false + + /@vue/compiler-dom@3.3.4: + resolution: {integrity: sha512-wyM+OjOVpuUukIq6p5+nwHYtj9cFroz9cwkfmP9O1nzH68BenTTv0u7/ndggT8cIQlnBeOo6sUT/gvHcIkLA5w==} + dependencies: + '@vue/compiler-core': 3.3.4 + '@vue/shared': 3.3.4 + dev: false + + /@vue/compiler-sfc@3.3.4: + resolution: {integrity: sha512-6y/d8uw+5TkCuzBkgLS0v3lSM3hJDntFEiUORM11pQ/hKvkhSKZrXW6i69UyXlJQisJxuUEJKAWEqWbWsLeNKQ==} + dependencies: + '@babel/parser': 7.25.6 + '@vue/compiler-core': 3.3.4 + '@vue/compiler-dom': 3.3.4 + '@vue/compiler-ssr': 3.3.4 + '@vue/reactivity-transform': 3.3.4 + '@vue/shared': 3.3.4 + estree-walker: 2.0.2 + magic-string: 0.30.11 + postcss: 8.4.45 + source-map-js: 1.2.0 + dev: false + + /@vue/compiler-ssr@3.3.4: + resolution: {integrity: sha512-m0v6oKpup2nMSehwA6Uuu+j+wEwcy7QmwMkVNVfrV9P2qE5KshC6RwOCq8fjGS/Eak/uNb8AaWekfiXxbBB6gQ==} + dependencies: + '@vue/compiler-dom': 3.3.4 + '@vue/shared': 3.3.4 + dev: false + + /@vue/reactivity-transform@3.3.4: + resolution: {integrity: sha512-MXgwjako4nu5WFLAjpBnCj/ieqcjE2aJBINUNQzkZQfzIZA4xn+0fV1tIYBJvvva3N3OvKGofRLvQIwEQPpaXw==} + dependencies: + '@babel/parser': 7.25.6 + '@vue/compiler-core': 3.3.4 + '@vue/shared': 3.3.4 + estree-walker: 2.0.2 + magic-string: 0.30.11 + dev: false + + /@vue/reactivity@3.3.4: + resolution: {integrity: sha512-kLTDLwd0B1jG08NBF3R5rqULtv/f8x3rOFByTDz4J53ttIQEDmALqKqXY0J+XQeN0aV2FBxY8nJDf88yvOPAqQ==} + dependencies: + '@vue/shared': 3.3.4 + dev: false + + /@vue/runtime-core@3.3.4: + resolution: {integrity: sha512-R+bqxMN6pWO7zGI4OMlmvePOdP2c93GsHFM/siJI7O2nxFRzj55pLwkpCedEY+bTMgp5miZ8CxfIZo3S+gFqvA==} + dependencies: + '@vue/reactivity': 3.3.4 + '@vue/shared': 3.3.4 + dev: false + + /@vue/runtime-dom@3.3.4: + resolution: {integrity: sha512-Aj5bTJ3u5sFsUckRghsNjVTtxZQ1OyMWCr5dZRAPijF/0Vy4xEoRCwLyHXcj4D0UFbJ4lbx3gPTgg06K/GnPnQ==} + dependencies: + '@vue/runtime-core': 3.3.4 + '@vue/shared': 3.3.4 + csstype: 3.1.3 + dev: false + + /@vue/server-renderer@3.3.4(vue@3.3.4): + resolution: {integrity: sha512-Q6jDDzR23ViIb67v+vM1Dqntu+HUexQcsWKhhQa4ARVzxOY2HbC7QRW/ggkDBd5BU+uM1sV6XOAP0b216o34JQ==} + peerDependencies: + vue: 3.3.4 + dependencies: + '@vue/compiler-ssr': 3.3.4 + '@vue/shared': 3.3.4 + vue: 3.3.4 + dev: false + + /@vue/shared@3.3.4: + resolution: {integrity: sha512-7OjdcV8vQ74eiz1TZLzZP4JwqM5fA94K6yntPS5Z25r9HDuGNzaGdgvwKYq6S+MxwF0TFRwe50fIR/MYnakdkQ==} + dev: false + + /abitype@1.0.5(typescript@5.5.4)(zod@3.23.8): + resolution: {integrity: sha512-YzDhti7cjlfaBhHutMaboYB21Ha3rXR9QTkNJFzYC4kC8YclaiwPBBBJY8ejFdu2wnJeZCVZSMlQJ7fi8S6hsw==} + peerDependencies: + typescript: '>=5.0.4' + zod: ^3 >=3.22.0 + peerDependenciesMeta: + typescript: + optional: true + zod: + optional: true + dependencies: + typescript: 5.5.4 + zod: 3.23.8 + dev: false + + /abortcontroller-polyfill@1.7.5: + resolution: {integrity: sha512-JMJ5soJWP18htbbxJjG7bG6yuI6pRhgJ0scHHTfkUjf6wjP912xZWvM+A4sJK3gqd9E8fcPbDnOefbA9Th/FIQ==} + dev: false + + /acorn-jsx@5.3.2(acorn@8.12.1): + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + acorn: 8.12.1 + + /acorn@8.12.1: + resolution: {integrity: sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==} + engines: {node: '>=0.4.0'} + hasBin: true + + /ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + /ansi-escapes@4.3.2: + resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} + engines: {node: '>=8'} + dependencies: + type-fest: 0.21.3 + dev: false + + /ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + /ansi-regex@6.0.1: + resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} + engines: {node: '>=12'} + + /ansi-styles@3.2.1: + resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} + engines: {node: '>=4'} + dependencies: + color-convert: 1.9.3 + + /ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + dependencies: + color-convert: 2.0.1 + + /ansi-styles@6.2.1: + resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} + engines: {node: '>=12'} + + /any-promise@1.3.0: + resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + + /anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + + /arg@5.0.2: + resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} + + /argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + /aria-hidden@1.2.4: + resolution: {integrity: sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==} + engines: {node: '>=10'} + dependencies: + tslib: 2.7.0 + dev: false + + /aria-query@5.3.0: + resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} + dependencies: + dequal: 2.0.3 + dev: false + + /array-buffer-byte-length@1.0.1: + resolution: {integrity: sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + is-array-buffer: 3.0.4 + dev: false + + /array-includes@3.1.8: + resolution: {integrity: sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-object-atoms: 1.0.0 + get-intrinsic: 1.2.4 + is-string: 1.0.7 + dev: false + + /array-union@2.1.0: + resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} + engines: {node: '>=8'} + + /array.prototype.findlast@1.2.5: + resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + es-shim-unscopables: 1.0.2 + dev: false + + /array.prototype.findlastindex@1.2.5: + resolution: {integrity: sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + es-shim-unscopables: 1.0.2 + dev: false + + /array.prototype.flat@1.3.2: + resolution: {integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-shim-unscopables: 1.0.2 + dev: false + + /array.prototype.flatmap@1.3.2: + resolution: {integrity: sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-shim-unscopables: 1.0.2 + dev: false + + /array.prototype.tosorted@1.1.4: + resolution: {integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-errors: 1.3.0 + es-shim-unscopables: 1.0.2 + dev: false + + /arraybuffer.prototype.slice@1.0.3: + resolution: {integrity: sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==} + engines: {node: '>= 0.4'} + dependencies: + array-buffer-byte-length: 1.0.1 + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-errors: 1.3.0 + get-intrinsic: 1.2.4 + is-array-buffer: 3.0.4 + is-shared-array-buffer: 1.0.3 + dev: false + + /autoprefixer@10.4.20(postcss@8.4.45): + resolution: {integrity: sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==} + engines: {node: ^10 || ^12 || >=14} + hasBin: true + peerDependencies: + postcss: ^8.1.0 + dependencies: + browserslist: 4.23.3 + caniuse-lite: 1.0.30001655 + fraction.js: 4.3.7 + normalize-range: 0.1.2 + picocolors: 1.1.0 + postcss: 8.4.45 + postcss-value-parser: 4.2.0 + dev: true + + /available-typed-arrays@1.0.7: + resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} + engines: {node: '>= 0.4'} + dependencies: + possible-typed-array-names: 1.0.0 + dev: false + + /axobject-query@3.2.4: + resolution: {integrity: sha512-aPTElBrbifBU1krmZxGZOlBkslORe7Ll7+BDnI50Wy4LgOt69luMgevkDfTq1O/ZgprooPCtWpjCwKSZw/iZ4A==} + engines: {node: '>= 0.4'} + dev: false + + /b4a@1.6.6: + resolution: {integrity: sha512-5Tk1HLk6b6ctmjIkAcU/Ujv/1WqiDl0F0JdRCR80VsOcUlHcu7pWeWRlOqQLHfDEsVx9YH/aif5AG4ehoCtTmg==} + dev: false + + /balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + /bare-events@2.4.2: + resolution: {integrity: sha512-qMKFd2qG/36aA4GwvKq8MxnPgCQAmBWmSyLWsJcbn8v03wvIPQ/hG1Ms8bPzndZxMDoHpxez5VOS+gC9Yi24/Q==} + requiresBuild: true + dev: false + optional: true + + /bare-fs@2.3.3: + resolution: {integrity: sha512-7RYKL+vZVCyAsMLi5SPu7QGauGGT8avnP/HO571ndEuV4MYdGXvLhtW67FuLPeEI8EiIY7zbbRR9x7x7HU0kgw==} + requiresBuild: true + dependencies: + bare-events: 2.4.2 + bare-path: 2.1.3 + bare-stream: 2.2.1 + dev: false + optional: true + + /bare-os@2.4.2: + resolution: {integrity: sha512-HZoJwzC+rZ9lqEemTMiO0luOePoGYNBgsLLgegKR/cljiJvcDNhDZQkzC+NC5Oh0aHbdBNSOHpghwMuB5tqhjg==} + requiresBuild: true + dev: false + optional: true + + /bare-path@2.1.3: + resolution: {integrity: sha512-lh/eITfU8hrj9Ru5quUp0Io1kJWIk1bTjzo7JH1P5dWmQ2EL4hFUlfI8FonAhSlgIfhn63p84CDY/x+PisgcXA==} + requiresBuild: true + dependencies: + bare-os: 2.4.2 + dev: false + optional: true + + /bare-stream@2.2.1: + resolution: {integrity: sha512-YTB47kHwBW9zSG8LD77MIBAAQXjU2WjAkMHeeb7hUplVs6+IoM5I7uEVQNPMB7lj9r8I76UMdoMkGnCodHOLqg==} + requiresBuild: true + dependencies: + b4a: 1.6.6 + streamx: 2.20.0 + dev: false + optional: true + + /base-x@3.0.10: + resolution: {integrity: sha512-7d0s06rR9rYaIWHkpfLIFICM/tkSVdoPC9qYAQRpxn9DdKNWNsKC0uk++akckyLq16Tx2WIinnZ6WRriAt6njQ==} + dependencies: + safe-buffer: 5.2.1 + dev: false + + /base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + dev: false + + /binary-extensions@2.3.0: + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} + engines: {node: '>=8'} + + /bl@4.1.0: + resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + dependencies: + buffer: 5.7.1 + inherits: 2.0.4 + readable-stream: 3.6.2 + dev: false + + /bluebird@3.7.2: + resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==} + dev: false + + /boolbase@1.0.0: + resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} + dev: false + + /brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + /brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + dependencies: + balanced-match: 1.0.2 + + /braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + dependencies: + fill-range: 7.1.1 + + /browserslist@4.22.1: + resolution: {integrity: sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + dependencies: + caniuse-lite: 1.0.30001655 + electron-to-chromium: 1.5.13 + node-releases: 2.0.18 + update-browserslist-db: 1.1.0(browserslist@4.22.1) + dev: false + + /browserslist@4.23.3: + resolution: {integrity: sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + dependencies: + caniuse-lite: 1.0.30001655 + electron-to-chromium: 1.5.13 + node-releases: 2.0.18 + update-browserslist-db: 1.1.0(browserslist@4.23.3) + + /buffer@5.7.1: + resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + dev: false + + /buffer@6.0.3: + resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + dev: false + + /bundle-require@4.2.1(esbuild@0.18.20): + resolution: {integrity: sha512-7Q/6vkyYAwOmQNRw75x+4yRtZCZJXUDmHHlFdkiV0wgv/reNjtJwpu1jPJ0w2kbEpIM0uoKI3S4/f39dU7AjSA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + peerDependencies: + esbuild: '>=0.17' + dependencies: + esbuild: 0.18.20 + load-tsconfig: 0.2.5 + dev: false + + /cac@6.7.14: + resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} + engines: {node: '>=8'} + dev: false + + /cacheable-lookup@7.0.0: + resolution: {integrity: sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==} + engines: {node: '>=14.16'} + dev: false + + /cacheable-request@10.2.14: + resolution: {integrity: sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==} + engines: {node: '>=14.16'} + dependencies: + '@types/http-cache-semantics': 4.0.4 + get-stream: 6.0.1 + http-cache-semantics: 4.1.1 + keyv: 4.5.4 + mimic-response: 4.0.0 + normalize-url: 8.0.1 + responselike: 3.0.0 + dev: false + + /call-bind@1.0.7: + resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} + engines: {node: '>= 0.4'} + dependencies: + es-define-property: 1.0.0 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.2.4 + set-function-length: 1.2.2 + dev: false + + /callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + /camelcase-css@2.0.1: + resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} + engines: {node: '>= 6'} + + /camelcase@6.3.0: + resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} + engines: {node: '>=10'} + dev: false + + /caniuse-lite@1.0.30001655: + resolution: {integrity: sha512-jRGVy3iSGO5Uutn2owlb5gR6qsGngTw9ZTb4ali9f3glshcNmJ2noam4Mo9zia5P9Dk3jNNydy7vQjuE5dQmfg==} + + /chalk@2.4.2: + resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} + engines: {node: '>=4'} + dependencies: + ansi-styles: 3.2.1 + escape-string-regexp: 1.0.5 + supports-color: 5.5.0 + + /chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + /chalk@5.3.0: + resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + dev: false + + /change-case@5.1.2: + resolution: {integrity: sha512-CAtbGEDulyjzs05RXy3uKcwqeztz/dMEuAc1Xu9NQBsbrhuGMneL0u9Dj5SoutLKBFYun8txxYIwhjtLNfUmCA==} + dev: false + + /chardet@0.7.0: + resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==} + dev: false + + /chokidar@3.6.0: + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} + engines: {node: '>= 8.10.0'} + dependencies: + anymatch: 3.1.3 + braces: 3.0.3 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + + /chownr@1.1.4: + resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} + dev: false + + /chrome-trace-event@1.0.4: + resolution: {integrity: sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==} + engines: {node: '>=6.0'} + dev: false + + /class-variance-authority@0.7.0: + resolution: {integrity: sha512-jFI8IQw4hczaL4ALINxqLEXQbWcNjoSkloa4IaufXCJr6QawJyw7tuRysRsrE8w2p/4gGaxKIt/hX3qz/IbD1A==} + dependencies: + clsx: 2.0.0 + dev: false + + /cli-cursor@3.1.0: + resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} + engines: {node: '>=8'} + dependencies: + restore-cursor: 3.1.0 + dev: false + + /cli-spinners@2.9.2: + resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} + engines: {node: '>=6'} + dev: false + + /cli-width@4.1.0: + resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==} + engines: {node: '>= 12'} + dev: false + + /clone@1.0.4: + resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} + engines: {node: '>=0.8'} + dev: false + + /clone@2.1.2: + resolution: {integrity: sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==} + engines: {node: '>=0.8'} + dev: false + + /clsx@2.0.0: + resolution: {integrity: sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==} + engines: {node: '>=6'} + dev: false + + /clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + dev: false + + /code-red@1.0.4: + resolution: {integrity: sha512-7qJWqItLA8/VPVlKJlFXU+NBlo/qyfs39aJcuMT/2ere32ZqvF5OSxgdM5xOfJJ7O429gg2HM47y8v9P+9wrNw==} + dependencies: + '@jridgewell/sourcemap-codec': 1.5.0 + '@types/estree': 1.0.5 + acorn: 8.12.1 + estree-walker: 3.0.3 + periscopic: 3.1.0 + dev: false + + /color-convert@1.9.3: + resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + dependencies: + color-name: 1.1.3 + + /color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + dependencies: + color-name: 1.1.4 + + /color-name@1.1.3: + resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} + + /color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + /color-string@1.9.1: + resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==} + dependencies: + color-name: 1.1.4 + simple-swizzle: 0.2.2 + dev: false + + /color@4.2.3: + resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} + engines: {node: '>=12.5.0'} + dependencies: + color-convert: 2.0.1 + color-string: 1.9.1 + dev: false + + /commander@4.1.1: + resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} + engines: {node: '>= 6'} + + /commander@7.2.0: + resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} + engines: {node: '>= 10'} + dev: false + + /concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + /config-chain@1.1.13: + resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==} + dependencies: + ini: 1.3.8 + proto-list: 1.2.4 + dev: false + + /content-security-policy-parser@0.4.1: + resolution: {integrity: sha512-NNJS8XPnx3OKr/CUOSwDSJw+lWTrZMYnclLKj0Y9CYOfJNJTWLFGPg3u2hYgbXMXKVRkZR2fbyReNQ1mUff/Qg==} + engines: {node: '>=8.0.0'} + dev: false + + /convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + /copy-anything@2.0.6: + resolution: {integrity: sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==} + dependencies: + is-what: 3.14.1 + dev: false + + /cosmiconfig@7.1.0: + resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==} + engines: {node: '>=10'} + dependencies: + '@types/parse-json': 4.0.2 + import-fresh: 3.3.0 + parse-json: 5.2.0 + path-type: 4.0.0 + yaml: 1.10.2 + dev: false + + /cosmiconfig@9.0.0(typescript@5.2.2): + resolution: {integrity: sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==} + engines: {node: '>=14'} + peerDependencies: + typescript: '>=4.9.5' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + env-paths: 2.2.1 + import-fresh: 3.3.0 + js-yaml: 4.1.0 + parse-json: 5.2.0 + typescript: 5.2.2 + dev: false + + /cross-spawn@7.0.3: + resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} + engines: {node: '>= 8'} + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + /crypto-random-string@4.0.0: + resolution: {integrity: sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==} + engines: {node: '>=12'} + dependencies: + type-fest: 1.4.0 + dev: false + + /css-select@4.3.0: + resolution: {integrity: sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==} + dependencies: + boolbase: 1.0.0 + css-what: 6.1.0 + domhandler: 4.3.1 + domutils: 2.8.0 + nth-check: 2.1.1 + dev: false + + /css-tree@1.1.3: + resolution: {integrity: sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==} + engines: {node: '>=8.0.0'} + dependencies: + mdn-data: 2.0.14 + source-map: 0.6.1 + dev: false + + /css-tree@2.3.1: + resolution: {integrity: sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} + dependencies: + mdn-data: 2.0.30 + source-map-js: 1.2.0 + dev: false + + /css-what@6.1.0: + resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==} + engines: {node: '>= 6'} + dev: false + + /cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true + + /csso@4.2.0: + resolution: {integrity: sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==} + engines: {node: '>=8.0.0'} + dependencies: + css-tree: 1.1.3 + dev: false + + /csstype@3.1.3: + resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + + /data-view-buffer@1.0.1: + resolution: {integrity: sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-data-view: 1.0.1 + dev: false + + /data-view-byte-length@1.0.1: + resolution: {integrity: sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-data-view: 1.0.1 + dev: false + + /data-view-byte-offset@1.0.0: + resolution: {integrity: sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-data-view: 1.0.1 + dev: false + + /debug@3.2.7: + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.3 + dev: false + + /debug@4.3.6: + resolution: {integrity: sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.2 + + /decompress-response@6.0.0: + resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} + engines: {node: '>=10'} + dependencies: + mimic-response: 3.1.0 + dev: false + + /deep-extend@0.6.0: + resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} + engines: {node: '>=4.0.0'} + dev: false + + /deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + + /deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + dev: false + + /defaults@1.0.4: + resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} + dependencies: + clone: 1.0.4 + dev: false + + /defer-to-connect@2.0.1: + resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==} + engines: {node: '>=10'} + dev: false + + /define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} + dependencies: + es-define-property: 1.0.0 + es-errors: 1.3.0 + gopd: 1.0.1 + dev: false + + /define-properties@1.2.1: + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} + engines: {node: '>= 0.4'} + dependencies: + define-data-property: 1.1.4 + has-property-descriptors: 1.0.2 + object-keys: 1.1.1 + dev: false + + /dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + dev: false + + /detect-libc@1.0.3: + resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==} + engines: {node: '>=0.10'} + hasBin: true + dev: false + + /detect-libc@2.0.3: + resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==} + engines: {node: '>=8'} + dev: false + + /detect-node-es@1.1.0: + resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} + dev: false + + /didyoumean@1.2.2: + resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} + + /dir-glob@3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + engines: {node: '>=8'} + dependencies: + path-type: 4.0.0 + + /dlv@1.1.3: + resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} + + /doctrine@2.1.0: + resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} + engines: {node: '>=0.10.0'} + dependencies: + esutils: 2.0.3 + dev: false + + /doctrine@3.0.0: + resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} + engines: {node: '>=6.0.0'} + dependencies: + esutils: 2.0.3 + + /dom-serializer@1.4.1: + resolution: {integrity: sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==} + dependencies: + domelementtype: 2.3.0 + domhandler: 4.3.1 + entities: 2.2.0 + dev: false + + /domelementtype@2.3.0: + resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} + dev: false + + /domhandler@4.3.1: + resolution: {integrity: sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==} + engines: {node: '>= 4'} + dependencies: + domelementtype: 2.3.0 + dev: false + + /domutils@2.8.0: + resolution: {integrity: sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==} + dependencies: + dom-serializer: 1.4.1 + domelementtype: 2.3.0 + domhandler: 4.3.1 + dev: false + + /dotenv-expand@10.0.0: + resolution: {integrity: sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==} + engines: {node: '>=12'} + dev: false + + /dotenv-expand@5.1.0: + resolution: {integrity: sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==} + dev: false + + /dotenv@16.3.1: + resolution: {integrity: sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==} + engines: {node: '>=12'} + dev: false + + /dotenv@16.4.5: + resolution: {integrity: sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==} + engines: {node: '>=12'} + dev: false + + /dotenv@7.0.0: + resolution: {integrity: sha512-M3NhsLbV1i6HuGzBUH8vXrtxOk+tWmzWKDMbAVSUp3Zsjm7ywFeuwrUXhmhQyRK1q5B5GGy7hcXPbj3bnfZg2g==} + engines: {node: '>=6'} + dev: false + + /dotenv@8.2.0: + resolution: {integrity: sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==} + engines: {node: '>=8'} + dev: false + + /eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + + /electron-to-chromium@1.5.13: + resolution: {integrity: sha512-lbBcvtIJ4J6sS4tb5TLp1b4LyfCdMkwStzXPyAgVgTRAsep4bvrAGaBOP7ZJtQMNJpSQ9SqG4brWOroNaQtm7Q==} + + /emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + /emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + + /end-of-stream@1.4.4: + resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} + dependencies: + once: 1.4.0 + dev: false + + /entities@2.2.0: + resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==} + dev: false + + /entities@3.0.1: + resolution: {integrity: sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==} + engines: {node: '>=0.12'} + dev: false + + /entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + dev: false + + /env-paths@2.2.1: + resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} + engines: {node: '>=6'} + dev: false + + /errno@0.1.8: + resolution: {integrity: sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==} + hasBin: true + requiresBuild: true + dependencies: + prr: 1.0.1 + dev: false + optional: true + + /error-ex@1.3.2: + resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + dependencies: + is-arrayish: 0.2.1 + dev: false + + /es-abstract@1.23.3: + resolution: {integrity: sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==} + engines: {node: '>= 0.4'} + dependencies: + array-buffer-byte-length: 1.0.1 + arraybuffer.prototype.slice: 1.0.3 + available-typed-arrays: 1.0.7 + call-bind: 1.0.7 + data-view-buffer: 1.0.1 + data-view-byte-length: 1.0.1 + data-view-byte-offset: 1.0.0 + es-define-property: 1.0.0 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + es-set-tostringtag: 2.0.3 + es-to-primitive: 1.2.1 + function.prototype.name: 1.1.6 + get-intrinsic: 1.2.4 + get-symbol-description: 1.0.2 + globalthis: 1.0.4 + gopd: 1.0.1 + has-property-descriptors: 1.0.2 + has-proto: 1.0.3 + has-symbols: 1.0.3 + hasown: 2.0.2 + internal-slot: 1.0.7 + is-array-buffer: 3.0.4 + is-callable: 1.2.7 + is-data-view: 1.0.1 + is-negative-zero: 2.0.3 + is-regex: 1.1.4 + is-shared-array-buffer: 1.0.3 + is-string: 1.0.7 + is-typed-array: 1.1.13 + is-weakref: 1.0.2 + object-inspect: 1.13.2 + object-keys: 1.1.1 + object.assign: 4.1.5 + regexp.prototype.flags: 1.5.2 + safe-array-concat: 1.1.2 + safe-regex-test: 1.0.3 + string.prototype.trim: 1.2.9 + string.prototype.trimend: 1.0.8 + string.prototype.trimstart: 1.0.8 + typed-array-buffer: 1.0.2 + typed-array-byte-length: 1.0.1 + typed-array-byte-offset: 1.0.2 + typed-array-length: 1.0.6 + unbox-primitive: 1.0.2 + which-typed-array: 1.1.15 + dev: false + + /es-define-property@1.0.0: + resolution: {integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.2.4 + dev: false + + /es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + dev: false + + /es-iterator-helpers@1.0.19: + resolution: {integrity: sha512-zoMwbCcH5hwUkKJkT8kDIBZSz9I6mVG//+lDCinLCGov4+r7NIy0ld8o03M0cJxl2spVf6ESYVS6/gpIfq1FFw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-errors: 1.3.0 + es-set-tostringtag: 2.0.3 + function-bind: 1.1.2 + get-intrinsic: 1.2.4 + globalthis: 1.0.4 + has-property-descriptors: 1.0.2 + has-proto: 1.0.3 + has-symbols: 1.0.3 + internal-slot: 1.0.7 + iterator.prototype: 1.1.2 + safe-array-concat: 1.1.2 + dev: false + + /es-object-atoms@1.0.0: + resolution: {integrity: sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==} + engines: {node: '>= 0.4'} + dependencies: + es-errors: 1.3.0 + dev: false + + /es-set-tostringtag@2.0.3: + resolution: {integrity: sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.2.4 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + dev: false + + /es-shim-unscopables@1.0.2: + resolution: {integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==} + dependencies: + hasown: 2.0.2 + dev: false + + /es-to-primitive@1.2.1: + resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} + engines: {node: '>= 0.4'} + dependencies: + is-callable: 1.2.7 + is-date-object: 1.0.5 + is-symbol: 1.0.4 + dev: false + + /esbuild@0.18.20: + resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/android-arm': 0.18.20 + '@esbuild/android-arm64': 0.18.20 + '@esbuild/android-x64': 0.18.20 + '@esbuild/darwin-arm64': 0.18.20 + '@esbuild/darwin-x64': 0.18.20 + '@esbuild/freebsd-arm64': 0.18.20 + '@esbuild/freebsd-x64': 0.18.20 + '@esbuild/linux-arm': 0.18.20 + '@esbuild/linux-arm64': 0.18.20 + '@esbuild/linux-ia32': 0.18.20 + '@esbuild/linux-loong64': 0.18.20 + '@esbuild/linux-mips64el': 0.18.20 + '@esbuild/linux-ppc64': 0.18.20 + '@esbuild/linux-riscv64': 0.18.20 + '@esbuild/linux-s390x': 0.18.20 + '@esbuild/linux-x64': 0.18.20 + '@esbuild/netbsd-x64': 0.18.20 + '@esbuild/openbsd-x64': 0.18.20 + '@esbuild/sunos-x64': 0.18.20 + '@esbuild/win32-arm64': 0.18.20 + '@esbuild/win32-ia32': 0.18.20 + '@esbuild/win32-x64': 0.18.20 + dev: false + + /esbuild@0.21.5: + resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/aix-ppc64': 0.21.5 + '@esbuild/android-arm': 0.21.5 + '@esbuild/android-arm64': 0.21.5 + '@esbuild/android-x64': 0.21.5 + '@esbuild/darwin-arm64': 0.21.5 + '@esbuild/darwin-x64': 0.21.5 + '@esbuild/freebsd-arm64': 0.21.5 + '@esbuild/freebsd-x64': 0.21.5 + '@esbuild/linux-arm': 0.21.5 + '@esbuild/linux-arm64': 0.21.5 + '@esbuild/linux-ia32': 0.21.5 + '@esbuild/linux-loong64': 0.21.5 + '@esbuild/linux-mips64el': 0.21.5 + '@esbuild/linux-ppc64': 0.21.5 + '@esbuild/linux-riscv64': 0.21.5 + '@esbuild/linux-s390x': 0.21.5 + '@esbuild/linux-x64': 0.21.5 + '@esbuild/netbsd-x64': 0.21.5 + '@esbuild/openbsd-x64': 0.21.5 + '@esbuild/sunos-x64': 0.21.5 + '@esbuild/win32-arm64': 0.21.5 + '@esbuild/win32-ia32': 0.21.5 + '@esbuild/win32-x64': 0.21.5 + dev: true + + /esbuild@0.23.1: + resolution: {integrity: sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==} + engines: {node: '>=18'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/aix-ppc64': 0.23.1 + '@esbuild/android-arm': 0.23.1 + '@esbuild/android-arm64': 0.23.1 + '@esbuild/android-x64': 0.23.1 + '@esbuild/darwin-arm64': 0.23.1 + '@esbuild/darwin-x64': 0.23.1 + '@esbuild/freebsd-arm64': 0.23.1 + '@esbuild/freebsd-x64': 0.23.1 + '@esbuild/linux-arm': 0.23.1 + '@esbuild/linux-arm64': 0.23.1 + '@esbuild/linux-ia32': 0.23.1 + '@esbuild/linux-loong64': 0.23.1 + '@esbuild/linux-mips64el': 0.23.1 + '@esbuild/linux-ppc64': 0.23.1 + '@esbuild/linux-riscv64': 0.23.1 + '@esbuild/linux-s390x': 0.23.1 + '@esbuild/linux-x64': 0.23.1 + '@esbuild/netbsd-x64': 0.23.1 + '@esbuild/openbsd-arm64': 0.23.1 + '@esbuild/openbsd-x64': 0.23.1 + '@esbuild/sunos-x64': 0.23.1 + '@esbuild/win32-arm64': 0.23.1 + '@esbuild/win32-ia32': 0.23.1 + '@esbuild/win32-x64': 0.23.1 + dev: true + + /escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + /escape-string-regexp@1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} + + /escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + /escape-string-regexp@5.0.0: + resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} + engines: {node: '>=12'} + dev: false + + /eslint-import-resolver-node@0.3.9: + resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} + dependencies: + debug: 3.2.7 + is-core-module: 2.15.1 + resolve: 1.22.8 + transitivePeerDependencies: + - supports-color + dev: false + + /eslint-module-utils@2.9.0(@typescript-eslint/parser@7.18.0)(eslint-import-resolver-node@0.3.9)(eslint@8.57.0): + resolution: {integrity: sha512-McVbYmwA3NEKwRQY5g4aWMdcZE5xZxV8i8l7CqJSrameuGSQJtSWaL/LxTEzSKKaCcOhlpDR8XEfYXWPrdo/ZQ==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: '*' + eslint-import-resolver-node: '*' + eslint-import-resolver-typescript: '*' + eslint-import-resolver-webpack: '*' + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint: + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: + optional: true + eslint-import-resolver-webpack: + optional: true + dependencies: + '@typescript-eslint/parser': 7.18.0(eslint@8.57.0)(typescript@5.5.4) + debug: 3.2.7 + eslint: 8.57.0 + eslint-import-resolver-node: 0.3.9 + transitivePeerDependencies: + - supports-color + dev: false + + /eslint-plugin-import@2.30.0(@typescript-eslint/parser@7.18.0)(eslint@8.57.0): + resolution: {integrity: sha512-/mHNE9jINJfiD2EKkg1BKyPyUk4zdnT54YgbOgfjSakWT5oyX/qQLVNTkehyfpcMxZXMy1zyonZ2v7hZTX43Yw==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + dependencies: + '@rtsao/scc': 1.1.0 + '@typescript-eslint/parser': 7.18.0(eslint@8.57.0)(typescript@5.5.4) + array-includes: 3.1.8 + array.prototype.findlastindex: 1.2.5 + array.prototype.flat: 1.3.2 + array.prototype.flatmap: 1.3.2 + debug: 3.2.7 + doctrine: 2.1.0 + eslint: 8.57.0 + eslint-import-resolver-node: 0.3.9 + eslint-module-utils: 2.9.0(@typescript-eslint/parser@7.18.0)(eslint-import-resolver-node@0.3.9)(eslint@8.57.0) + hasown: 2.0.2 + is-core-module: 2.15.1 + is-glob: 4.0.3 + minimatch: 3.1.2 + object.fromentries: 2.0.8 + object.groupby: 1.0.3 + object.values: 1.2.0 + semver: 6.3.1 + tsconfig-paths: 3.15.0 + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + dev: false + + /eslint-plugin-react-hooks@4.6.2(eslint@8.57.0): + resolution: {integrity: sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==} + engines: {node: '>=10'} + peerDependencies: + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 + dependencies: + eslint: 8.57.0 + dev: true + + /eslint-plugin-react-refresh@0.4.11(eslint@8.57.0): + resolution: {integrity: sha512-wrAKxMbVr8qhXTtIKfXqAn5SAtRZt0aXxe5P23Fh4pUAdC6XEsybGLB8P0PI4j1yYqOgUEUlzKAGDfo7rJOjcw==} + peerDependencies: + eslint: '>=7' + dependencies: + eslint: 8.57.0 + dev: true + + /eslint-plugin-react@7.35.2(eslint@8.57.0): + resolution: {integrity: sha512-Rbj2R9zwP2GYNcIak4xoAMV57hrBh3hTaR0k7hVjwCQgryE/pw5px4b13EYjduOI0hfXyZhwBxaGpOTbWSGzKQ==} + engines: {node: '>=4'} + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 + dependencies: + array-includes: 3.1.8 + array.prototype.findlast: 1.2.5 + array.prototype.flatmap: 1.3.2 + array.prototype.tosorted: 1.1.4 + doctrine: 2.1.0 + es-iterator-helpers: 1.0.19 + eslint: 8.57.0 + estraverse: 5.3.0 + hasown: 2.0.2 + jsx-ast-utils: 3.3.5 + minimatch: 3.1.2 + object.entries: 1.1.8 + object.fromentries: 2.0.8 + object.values: 1.2.0 + prop-types: 15.8.1 + resolve: 2.0.0-next.5 + semver: 6.3.1 + string.prototype.matchall: 4.0.11 + string.prototype.repeat: 1.0.0 + dev: false + + /eslint-scope@7.2.2: + resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + /eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + /eslint@8.57.0: + resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + hasBin: true + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) + '@eslint-community/regexpp': 4.11.0 + '@eslint/eslintrc': 2.1.4 + '@eslint/js': 8.57.0 + '@humanwhocodes/config-array': 0.11.14 + '@humanwhocodes/module-importer': 1.0.1 + '@nodelib/fs.walk': 1.2.8 + '@ungap/structured-clone': 1.2.0 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.3 + debug: 4.3.6 + doctrine: 3.0.0 + escape-string-regexp: 4.0.0 + eslint-scope: 7.2.2 + eslint-visitor-keys: 3.4.3 + espree: 9.6.1 + esquery: 1.6.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 6.0.1 + find-up: 5.0.0 + glob-parent: 6.0.2 + globals: 13.24.0 + graphemer: 1.4.0 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + is-path-inside: 3.0.3 + js-yaml: 4.1.0 + json-stable-stringify-without-jsonify: 1.0.1 + levn: 0.4.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.4 + strip-ansi: 6.0.1 + text-table: 0.2.0 + transitivePeerDependencies: + - supports-color + + /espree@9.6.1: + resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + acorn: 8.12.1 + acorn-jsx: 5.3.2(acorn@8.12.1) + eslint-visitor-keys: 3.4.3 + + /esquery@1.6.0: + resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} + engines: {node: '>=0.10'} + dependencies: + estraverse: 5.3.0 + + /esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + dependencies: + estraverse: 5.3.0 + + /estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + /estree-walker@2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + dev: false + + /estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + dependencies: + '@types/estree': 1.0.5 + dev: false + + /esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + /events@3.3.0: + resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} + engines: {node: '>=0.8.x'} + dev: false + + /execa@5.1.1: + resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} + engines: {node: '>=10'} + dependencies: + cross-spawn: 7.0.3 + get-stream: 6.0.1 + human-signals: 2.1.0 + is-stream: 2.0.1 + merge-stream: 2.0.0 + npm-run-path: 4.0.1 + onetime: 5.1.2 + signal-exit: 3.0.7 + strip-final-newline: 2.0.0 + dev: false + + /expand-template@2.0.3: + resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} + engines: {node: '>=6'} + dev: false + + /external-editor@3.1.0: + resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==} + engines: {node: '>=4'} + dependencies: + chardet: 0.7.0 + iconv-lite: 0.4.24 + tmp: 0.0.33 + dev: false + + /fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + /fast-fifo@1.3.2: + resolution: {integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==} + dev: false + + /fast-glob@3.3.2: + resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} + engines: {node: '>=8.6.0'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + /fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + /fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + + /fastq@1.17.1: + resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} + dependencies: + reusify: 1.0.4 + + /fflate@0.8.1: + resolution: {integrity: sha512-/exOvEuc+/iaUm105QIiOt4LpBdMTWsXxqR0HDF35vx3fmaKzw7354gTilCh5rkzEt8WYyG//ku3h3nRmd7CHQ==} + dev: false + + /figures@5.0.0: + resolution: {integrity: sha512-ej8ksPF4x6e5wvK9yevct0UCXh8TTFlWGVLlgjZuoBH1HwjIfKE/IdL5mq89sFA7zELi1VhKpmtDnrs7zWyeyg==} + engines: {node: '>=14'} + dependencies: + escape-string-regexp: 5.0.0 + is-unicode-supported: 1.3.0 + dev: false + + /file-entry-cache@6.0.1: + resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} + engines: {node: ^10.12.0 || >=12.0.0} + dependencies: + flat-cache: 3.2.0 + + /fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + dependencies: + to-regex-range: 5.0.1 + + /find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + /flat-cache@3.2.0: + resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} + engines: {node: ^10.12.0 || >=12.0.0} + dependencies: + flatted: 3.3.1 + keyv: 4.5.4 + rimraf: 3.0.2 + + /flatted@3.3.1: + resolution: {integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==} + + /for-each@0.3.3: + resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} + dependencies: + is-callable: 1.2.7 + dev: false + + /foreground-child@3.3.0: + resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==} + engines: {node: '>=14'} + dependencies: + cross-spawn: 7.0.3 + signal-exit: 4.1.0 + + /form-data-encoder@2.1.4: + resolution: {integrity: sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==} + engines: {node: '>= 14.17'} + dev: false + + /fraction.js@4.3.7: + resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} + dev: true + + /fs-constants@1.0.0: + resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} + dev: false + + /fs-extra@10.1.0: + resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} + engines: {node: '>=12'} + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 2.0.1 + dev: true + + /fs-extra@11.1.1: + resolution: {integrity: sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==} + engines: {node: '>=14.14'} + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 2.0.1 + dev: false + + /fs-extra@11.2.0: + resolution: {integrity: sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==} + engines: {node: '>=14.14'} + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 2.0.1 + dev: true + + /fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + + /fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + requiresBuild: true + optional: true + + /function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + /function.prototype.name@1.1.6: + resolution: {integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + functions-have-names: 1.2.3 + dev: false + + /functions-have-names@1.2.3: + resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + dev: false + + /gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + + /get-intrinsic@1.2.4: + resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} + engines: {node: '>= 0.4'} + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + has-proto: 1.0.3 + has-symbols: 1.0.3 + hasown: 2.0.2 + dev: false + + /get-nonce@1.0.1: + resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} + engines: {node: '>=6'} + dev: false + + /get-port@7.0.0: + resolution: {integrity: sha512-mDHFgApoQd+azgMdwylJrv2DX47ywGq1i5VFJE7fZ0dttNq3iQMfsU4IvEgBHojA3KqEudyu7Vq+oN8kNaNkWw==} + engines: {node: '>=16'} + dev: false + + /get-stream@6.0.1: + resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} + engines: {node: '>=10'} + dev: false + + /get-symbol-description@1.0.2: + resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + get-intrinsic: 1.2.4 + dev: false + + /get-tsconfig@4.8.1: + resolution: {integrity: sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==} + dependencies: + resolve-pkg-maps: 1.0.0 + dev: true + + /github-from-package@0.0.0: + resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==} + dev: false + + /glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + dependencies: + is-glob: 4.0.3 + + /glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + dependencies: + is-glob: 4.0.3 + + /glob@10.4.5: + resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} + hasBin: true + dependencies: + foreground-child: 3.3.0 + jackspeak: 3.4.3 + minimatch: 9.0.5 + minipass: 7.1.2 + package-json-from-dist: 1.0.0 + path-scurry: 1.11.1 + + /glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + deprecated: Glob versions prior to v9 are no longer supported + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + + /globals@11.12.0: + resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} + engines: {node: '>=4'} + + /globals@13.24.0: + resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} + engines: {node: '>=8'} + dependencies: + type-fest: 0.20.2 + + /globalthis@1.0.4: + resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} + engines: {node: '>= 0.4'} + dependencies: + define-properties: 1.2.1 + gopd: 1.0.1 + dev: false + + /globby@11.1.0: + resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} + engines: {node: '>=10'} + dependencies: + array-union: 2.1.0 + dir-glob: 3.0.1 + fast-glob: 3.3.2 + ignore: 5.3.2 + merge2: 1.4.1 + slash: 3.0.0 + + /globrex@0.1.2: + resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} + dev: true + + /gopd@1.0.1: + resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} + dependencies: + get-intrinsic: 1.2.4 + dev: false + + /got@12.6.1: + resolution: {integrity: sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==} + engines: {node: '>=14.16'} + dependencies: + '@sindresorhus/is': 5.6.0 + '@szmarczak/http-timer': 5.0.1 + cacheable-lookup: 7.0.0 + cacheable-request: 10.2.14 + decompress-response: 6.0.0 + form-data-encoder: 2.1.4 + get-stream: 6.0.1 + http2-wrapper: 2.2.1 + lowercase-keys: 3.0.0 + p-cancelable: 3.0.0 + responselike: 3.0.0 + dev: false + + /got@13.0.0: + resolution: {integrity: sha512-XfBk1CxOOScDcMr9O1yKkNaQyy865NbYs+F7dr4H0LZMVgCj2Le59k6PqbNHoL5ToeaEQUYh6c6yMfVcc6SJxA==} + engines: {node: '>=16'} + dependencies: + '@sindresorhus/is': 5.6.0 + '@szmarczak/http-timer': 5.0.1 + cacheable-lookup: 7.0.0 + cacheable-request: 10.2.14 + decompress-response: 6.0.0 + form-data-encoder: 2.1.4 + get-stream: 6.0.1 + http2-wrapper: 2.2.1 + lowercase-keys: 3.0.0 + p-cancelable: 3.0.0 + responselike: 3.0.0 + dev: false + + /graceful-fs@4.2.10: + resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==} + dev: false + + /graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + /graphemer@1.4.0: + resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + + /graphql-import-macro@1.0.0: + resolution: {integrity: sha512-YK4g6iP60H++MpP93tb0VwOg7aM5iIC0hdSQKTrEDANeLWf0KFAT9dwlBeMDrhY+jcW7qsAEDtaw58cgVnQXAw==} + dependencies: + graphql: 15.9.0 + dev: false + + /graphql@15.9.0: + resolution: {integrity: sha512-GCOQdvm7XxV1S4U4CGrsdlEN37245eC8P9zaYCMr6K1BG0IPGy5lUwmJsEOGyl1GD6HXjOtl2keCP9asRBwNvA==} + engines: {node: '>= 10.x'} + dev: false + + /has-bigints@1.0.2: + resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} + dev: false + + /has-flag@3.0.0: + resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} + engines: {node: '>=4'} + + /has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + /has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + dependencies: + es-define-property: 1.0.0 + dev: false + + /has-proto@1.0.3: + resolution: {integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==} + engines: {node: '>= 0.4'} + dev: false + + /has-symbols@1.0.3: + resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} + engines: {node: '>= 0.4'} + dev: false + + /has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + dependencies: + has-symbols: 1.0.3 + dev: false + + /hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + dependencies: + function-bind: 1.1.2 + + /htmlnano@2.1.1(postcss@8.4.45)(svgo@2.8.0)(typescript@5.2.2): + resolution: {integrity: sha512-kAERyg/LuNZYmdqgCdYvugyLWNFAm8MWXpQMz1pLpetmCbFwoMxvkSoaAMlFrOC4OKTWI4KlZGT/RsNxg4ghOw==} + peerDependencies: + cssnano: ^7.0.0 + postcss: ^8.3.11 + purgecss: ^6.0.0 + relateurl: ^0.2.7 + srcset: 5.0.1 + svgo: ^3.0.2 + terser: ^5.10.0 + uncss: ^0.17.3 + peerDependenciesMeta: + cssnano: + optional: true + postcss: + optional: true + purgecss: + optional: true + relateurl: + optional: true + srcset: + optional: true + svgo: + optional: true + terser: + optional: true + uncss: + optional: true + dependencies: + cosmiconfig: 9.0.0(typescript@5.2.2) + postcss: 8.4.45 + posthtml: 0.16.6 + svgo: 2.8.0 + timsort: 0.3.0 + transitivePeerDependencies: + - typescript + dev: false + + /htmlparser2@7.2.0: + resolution: {integrity: sha512-H7MImA4MS6cw7nbyURtLPO1Tms7C5H602LRETv95z1MxO/7CP7rDVROehUYeYBUYEON94NXXDEPmZuq+hX4sog==} + dependencies: + domelementtype: 2.3.0 + domhandler: 4.3.1 + domutils: 2.8.0 + entities: 3.0.1 + dev: false + + /http-cache-semantics@4.1.1: + resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==} + dev: false + + /http2-wrapper@2.2.1: + resolution: {integrity: sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==} + engines: {node: '>=10.19.0'} + dependencies: + quick-lru: 5.1.1 + resolve-alpn: 1.2.1 + dev: false + + /human-signals@2.1.0: + resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} + engines: {node: '>=10.17.0'} + dev: false + + /iconv-lite@0.4.24: + resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} + engines: {node: '>=0.10.0'} + dependencies: + safer-buffer: 2.1.2 + dev: false + + /iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + requiresBuild: true + dependencies: + safer-buffer: 2.1.2 + dev: false + optional: true + + /ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + dev: false + + /ignore@5.2.4: + resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==} + engines: {node: '>= 4'} + dev: false + + /ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + /image-size@0.5.5: + resolution: {integrity: sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==} + engines: {node: '>=0.10.0'} + hasBin: true + requiresBuild: true + dev: false + optional: true + + /immutable@4.3.7: + resolution: {integrity: sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==} + dev: false + + /import-fresh@3.3.0: + resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} + engines: {node: '>=6'} + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + /imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + /inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + + /inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + /ini@1.3.8: + resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + dev: false + + /inquirer@9.2.12: + resolution: {integrity: sha512-mg3Fh9g2zfuVWJn6lhST0O7x4n03k7G8Tx5nvikJkbq8/CK47WDVm+UznF0G6s5Zi0KcyUisr6DU8T67N5U+1Q==} + engines: {node: '>=14.18.0'} + dependencies: + '@ljharb/through': 2.3.13 + ansi-escapes: 4.3.2 + chalk: 5.3.0 + cli-cursor: 3.1.0 + cli-width: 4.1.0 + external-editor: 3.1.0 + figures: 5.0.0 + lodash: 4.17.21 + mute-stream: 1.0.0 + ora: 5.4.1 + run-async: 3.0.0 + rxjs: 7.8.1 + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 6.2.0 + dev: false + + /internal-slot@1.0.7: + resolution: {integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==} + engines: {node: '>= 0.4'} + dependencies: + es-errors: 1.3.0 + hasown: 2.0.2 + side-channel: 1.0.6 + dev: false + + /invariant@2.2.4: + resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==} + dependencies: + loose-envify: 1.4.0 + dev: false + + /is-array-buffer@3.0.4: + resolution: {integrity: sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + get-intrinsic: 1.2.4 + dev: false + + /is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + dev: false + + /is-arrayish@0.3.2: + resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==} + dev: false + + /is-async-function@2.0.0: + resolution: {integrity: sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.2 + dev: false + + /is-bigint@1.0.4: + resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} + dependencies: + has-bigints: 1.0.2 + dev: false + + /is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + dependencies: + binary-extensions: 2.3.0 + + /is-boolean-object@1.1.2: + resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + has-tostringtag: 1.0.2 + dev: false + + /is-callable@1.2.7: + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} + engines: {node: '>= 0.4'} + dev: false + + /is-core-module@2.15.1: + resolution: {integrity: sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==} + engines: {node: '>= 0.4'} + dependencies: + hasown: 2.0.2 + + /is-data-view@1.0.1: + resolution: {integrity: sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==} + engines: {node: '>= 0.4'} + dependencies: + is-typed-array: 1.1.13 + dev: false + + /is-date-object@1.0.5: + resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.2 + dev: false + + /is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + /is-finalizationregistry@1.0.2: + resolution: {integrity: sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==} + dependencies: + call-bind: 1.0.7 + dev: false + + /is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + /is-generator-function@1.0.10: + resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.2 + dev: false + + /is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + dependencies: + is-extglob: 2.1.1 + + /is-interactive@1.0.0: + resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==} + engines: {node: '>=8'} + dev: false + + /is-json@2.0.1: + resolution: {integrity: sha512-6BEnpVn1rcf3ngfmViLM6vjUjGErbdrL4rwlv+u1NO1XO8kqT4YGL8+19Q+Z/bas8tY90BTWMk2+fW1g6hQjbA==} + dev: false + + /is-map@2.0.3: + resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} + engines: {node: '>= 0.4'} + dev: false + + /is-negative-zero@2.0.3: + resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} + engines: {node: '>= 0.4'} + dev: false + + /is-number-object@1.0.7: + resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.2 + dev: false + + /is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + /is-path-inside@3.0.3: + resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} + engines: {node: '>=8'} + + /is-path-inside@4.0.0: + resolution: {integrity: sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==} + engines: {node: '>=12'} + dev: false + + /is-reference@3.0.2: + resolution: {integrity: sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==} + dependencies: + '@types/estree': 1.0.5 + dev: false + + /is-regex@1.1.4: + resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + has-tostringtag: 1.0.2 + dev: false + + /is-set@2.0.3: + resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} + engines: {node: '>= 0.4'} + dev: false + + /is-shared-array-buffer@1.0.3: + resolution: {integrity: sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + dev: false + + /is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + dev: false + + /is-stream@3.0.0: + resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: false + + /is-string@1.0.7: + resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} + engines: {node: '>= 0.4'} + dependencies: + has-tostringtag: 1.0.2 + dev: false + + /is-symbol@1.0.4: + resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==} + engines: {node: '>= 0.4'} + dependencies: + has-symbols: 1.0.3 + dev: false + + /is-typed-array@1.1.13: + resolution: {integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==} + engines: {node: '>= 0.4'} + dependencies: + which-typed-array: 1.1.15 + dev: false + + /is-unicode-supported@0.1.0: + resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} + engines: {node: '>=10'} + dev: false + + /is-unicode-supported@1.3.0: + resolution: {integrity: sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==} + engines: {node: '>=12'} + dev: false + + /is-weakmap@2.0.2: + resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} + engines: {node: '>= 0.4'} + dev: false + + /is-weakref@1.0.2: + resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} + dependencies: + call-bind: 1.0.7 + dev: false + + /is-weakset@2.0.3: + resolution: {integrity: sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + get-intrinsic: 1.2.4 + dev: false + + /is-what@3.14.1: + resolution: {integrity: sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==} + dev: false + + /isarray@2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + dev: false + + /isbinaryfile@4.0.10: + resolution: {integrity: sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==} + engines: {node: '>= 8.0.0'} + dev: false + + /isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + /isows@1.0.4(ws@8.17.1): + resolution: {integrity: sha512-hEzjY+x9u9hPmBom9IIAqdJCwNLax+xrPb51vEPpERoFlIxgmZcHzsT5jKG06nvInKOBGvReAVz80Umed5CczQ==} + peerDependencies: + ws: '*' + dependencies: + ws: 8.17.1 + dev: false + + /iterator.prototype@1.1.2: + resolution: {integrity: sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==} + dependencies: + define-properties: 1.2.1 + get-intrinsic: 1.2.4 + has-symbols: 1.0.3 + reflect.getprototypeof: 1.0.6 + set-function-name: 2.0.2 + dev: false + + /jackspeak@3.4.3: + resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + + /jiti@1.21.6: + resolution: {integrity: sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==} + hasBin: true + + /joycon@3.1.1: + resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} + engines: {node: '>=10'} + dev: false + + /js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + /js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + dependencies: + argparse: 2.0.1 + + /jsesc@2.5.2: + resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} + engines: {node: '>=4'} + hasBin: true + + /json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + /json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + dev: false + + /json-schema-to-ts@2.9.2: + resolution: {integrity: sha512-h9WqLkTVpBbiaPb5OmeUpz/FBLS/kvIJw4oRCPiEisIu2WjMh+aai0QIY2LoOhRFx5r92taGLcerIrzxKBAP6g==} + engines: {node: '>=16'} + dependencies: + '@babel/runtime': 7.25.6 + '@types/json-schema': 7.0.15 + ts-algebra: 1.2.2 + dev: false + + /json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + /json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + + /json5@1.0.2: + resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} + hasBin: true + dependencies: + minimist: 1.2.8 + dev: false + + /json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + /jsonfile@6.1.0: + resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} + dependencies: + universalify: 2.0.1 + optionalDependencies: + graceful-fs: 4.2.11 + + /jsx-ast-utils@3.3.5: + resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} + engines: {node: '>=4.0'} + dependencies: + array-includes: 3.1.8 + array.prototype.flat: 1.3.2 + object.assign: 4.1.5 + object.values: 1.2.0 + dev: false + + /keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + dependencies: + json-buffer: 3.0.1 + + /less@4.2.0: + resolution: {integrity: sha512-P3b3HJDBtSzsXUl0im2L7gTO5Ubg8mEN6G8qoTS77iXxXX4Hvu4Qj540PZDvQ8V6DmX6iXo98k7Md0Cm1PrLaA==} + engines: {node: '>=6'} + hasBin: true + dependencies: + copy-anything: 2.0.6 + parse-node-version: 1.0.1 + tslib: 2.7.0 + optionalDependencies: + errno: 0.1.8 + graceful-fs: 4.2.11 + image-size: 0.5.5 + make-dir: 2.1.0 + mime: 1.6.0 + needle: 3.3.1 + source-map: 0.6.1 + dev: false + + /levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + + /lightningcss-darwin-arm64@1.21.8: + resolution: {integrity: sha512-BOMoGfcgkk2f4ltzsJqmkjiqRtlZUK+UdwhR+P6VgIsnpQBV3G01mlL6GzYxYqxq+6/3/n/D+4oy2NeknmADZw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /lightningcss-darwin-arm64@1.26.0: + resolution: {integrity: sha512-n4TIvHO1NY1ondKFYpL2ZX0bcC2y6yjXMD6JfyizgR8BCFNEeArINDzEaeqlfX9bXz73Bpz/Ow0nu+1qiDrBKg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /lightningcss-darwin-x64@1.21.8: + resolution: {integrity: sha512-YhF64mcVDPKKufL4aNFBnVH7uvzE0bW3YUsPXdP4yUcT/8IXChypOZ/PE1pmt2RlbmsyVuuIIeZU4zTyZe5Amw==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /lightningcss-darwin-x64@1.26.0: + resolution: {integrity: sha512-Rf9HuHIDi1R6/zgBkJh25SiJHF+dm9axUZW/0UoYCW1/8HV0gMI0blARhH4z+REmWiU1yYT/KyNF3h7tHyRXUg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /lightningcss-freebsd-x64@1.21.8: + resolution: {integrity: sha512-CV6A/vTG2Ryd3YpChEgfWWv4TXCAETo9TcHSNx0IP0dnKcnDEiAko4PIKhCqZL11IGdN1ZLBCVPw+vw5ZYwzfA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: false + optional: true + + /lightningcss-freebsd-x64@1.26.0: + resolution: {integrity: sha512-C/io7POAxp6sZxFSVGezjajMlCKQ8KSwISLLGRq8xLQpQMokYrUoqYEwmIX8mLmF6C/CZPk0gFmRSzd8biWM0g==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: false + optional: true + + /lightningcss-linux-arm-gnueabihf@1.21.8: + resolution: {integrity: sha512-9PMbqh8n/Xq0F4/j2NR/hHM2HRDiFXFSF0iOvV67pNWKJkHIO6mR8jBw/88Aro5Ye/ILsX5OuWsxIVJDFv0NXA==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /lightningcss-linux-arm-gnueabihf@1.26.0: + resolution: {integrity: sha512-Aag9kqXqkyPSW+dXMgyWk66C984Nay2pY8Nws+67gHlDzV3cWh7TvFlzuaTaVFMVqdDTzN484LSK3u39zFBnzg==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /lightningcss-linux-arm64-gnu@1.21.8: + resolution: {integrity: sha512-JTM/TuMMllkzaXV7/eDjG4IJKLlCl+RfYZwtsVmC82gc0QX0O37csGAcY2OGleiuA4DnEo/Qea5WoFfZUNC6zg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /lightningcss-linux-arm64-gnu@1.26.0: + resolution: {integrity: sha512-iJmZM7fUyVjH+POtdiCtExG+67TtPUTer7K/5A8DIfmPfrmeGvzfRyBltGhQz13Wi15K1lf2cPYoRaRh6vcwNA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /lightningcss-linux-arm64-musl@1.21.8: + resolution: {integrity: sha512-01gWShXrgoIb8urzShpn1RWtZuaSyKSzF2hfO+flzlTPoACqcO3rgcu/3af4Cw54e8vKzL5hPRo4kROmgaOMLg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /lightningcss-linux-arm64-musl@1.26.0: + resolution: {integrity: sha512-XxoEL++tTkyuvu+wq/QS8bwyTXZv2y5XYCMcWL45b8XwkiS8eEEEej9BkMGSRwxa5J4K+LDeIhLrS23CpQyfig==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /lightningcss-linux-x64-gnu@1.21.8: + resolution: {integrity: sha512-yVB5vYJjJb/Aku0V9QaGYIntvK/1TJOlNB9GmkNpXX5bSSP2pYW4lWW97jxFMHO908M0zjEt1qyOLMyqojHL+Q==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /lightningcss-linux-x64-gnu@1.26.0: + resolution: {integrity: sha512-1dkTfZQAYLj8MUSkd6L/+TWTG8V6Kfrzfa0T1fSlXCXQHrt1HC1/UepXHtKHDt/9yFwyoeayivxXAsApVxn6zA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /lightningcss-linux-x64-musl@1.21.8: + resolution: {integrity: sha512-TYi+KNtBVK0+FZvxTX/d5XJb+tw3Jq+2Rr9hW359wp1afsi1Vkg+uVGgbn+m2dipa5XwpCseQq81ylMlXuyfPw==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /lightningcss-linux-x64-musl@1.26.0: + resolution: {integrity: sha512-yX3Rk9m00JGCUzuUhFEojY+jf/6zHs3XU8S8Vk+FRbnr4St7cjyMXdNjuA2LjiT8e7j8xHRCH8hyZ4H/btRE4A==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /lightningcss-win32-arm64-msvc@1.26.0: + resolution: {integrity: sha512-X/597/cFnCogy9VItj/+7Tgu5VLbAtDF7KZDPdSw0MaL6FL940th1y3HiOzFIlziVvAtbo0RB3NAae1Oofr+Tw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /lightningcss-win32-x64-msvc@1.21.8: + resolution: {integrity: sha512-mww+kqbPx0/C44l2LEloECtRUuOFDjq9ftp+EHTPiCp2t+avy0sh8MaFwGsrKkj2XfZhaRhi4CPVKBoqF1Qlwg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /lightningcss-win32-x64-msvc@1.26.0: + resolution: {integrity: sha512-pYS3EyGP3JRhfqEFYmfFDiZ9/pVNfy8jVIYtrx9TVNusVyDK3gpW1w/rbvroQ4bDJi7grdUtyrYU6V2xkY/bBw==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /lightningcss@1.21.8: + resolution: {integrity: sha512-jEqaL7m/ZckZJjlMAfycr1Kpz7f93k6n7KGF5SJjuPSm6DWI6h3ayLZmgRHgy1OfrwoCed6h4C/gHYPOd1OFMA==} + engines: {node: '>= 12.0.0'} + dependencies: + detect-libc: 1.0.3 + optionalDependencies: + lightningcss-darwin-arm64: 1.21.8 + lightningcss-darwin-x64: 1.21.8 + lightningcss-freebsd-x64: 1.21.8 + lightningcss-linux-arm-gnueabihf: 1.21.8 + lightningcss-linux-arm64-gnu: 1.21.8 + lightningcss-linux-arm64-musl: 1.21.8 + lightningcss-linux-x64-gnu: 1.21.8 + lightningcss-linux-x64-musl: 1.21.8 + lightningcss-win32-x64-msvc: 1.21.8 + dev: false + + /lightningcss@1.26.0: + resolution: {integrity: sha512-a/XZ5hdgifrofQJUArr5AiJjx26SwMam3SJUSMjgebZbESZ96i+6Qsl8tLi0kaUsdMzBWXh9sN1Oe6hp2/dkQw==} + engines: {node: '>= 12.0.0'} + dependencies: + detect-libc: 1.0.3 + optionalDependencies: + lightningcss-darwin-arm64: 1.26.0 + lightningcss-darwin-x64: 1.26.0 + lightningcss-freebsd-x64: 1.26.0 + lightningcss-linux-arm-gnueabihf: 1.26.0 + lightningcss-linux-arm64-gnu: 1.26.0 + lightningcss-linux-arm64-musl: 1.26.0 + lightningcss-linux-x64-gnu: 1.26.0 + lightningcss-linux-x64-musl: 1.26.0 + lightningcss-win32-arm64-msvc: 1.26.0 + lightningcss-win32-x64-msvc: 1.26.0 + dev: false + + /lilconfig@2.1.0: + resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} + engines: {node: '>=10'} + + /lilconfig@3.1.2: + resolution: {integrity: sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==} + engines: {node: '>=14'} + + /lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + + /lmdb@2.5.2: + resolution: {integrity: sha512-V5V5Xa2Hp9i2XsbDALkBTeHXnBXh/lEmk9p22zdr7jtuOIY9TGhjK6vAvTpOOx9IKU4hJkRWZxn/HsvR1ELLtA==} + requiresBuild: true + dependencies: + msgpackr: 1.11.0 + node-addon-api: 4.3.0 + node-gyp-build-optional-packages: 5.0.3 + ordered-binary: 1.5.1 + weak-lru-cache: 1.2.2 + optionalDependencies: + '@lmdb/lmdb-darwin-arm64': 2.5.2 + '@lmdb/lmdb-darwin-x64': 2.5.2 + '@lmdb/lmdb-linux-arm': 2.5.2 + '@lmdb/lmdb-linux-arm64': 2.5.2 + '@lmdb/lmdb-linux-x64': 2.5.2 + '@lmdb/lmdb-win32-x64': 2.5.2 + dev: false + + /lmdb@2.7.11: + resolution: {integrity: sha512-x9bD4hVp7PFLUoELL8RglbNXhAMt5CYhkmss+CEau9KlNoilsTzNi9QDsPZb3KMpOGZXG6jmXhW3bBxE2XVztw==} + hasBin: true + requiresBuild: true + dependencies: + msgpackr: 1.8.5 + node-addon-api: 4.3.0 + node-gyp-build-optional-packages: 5.0.6 + ordered-binary: 1.5.1 + weak-lru-cache: 1.2.2 + optionalDependencies: + '@lmdb/lmdb-darwin-arm64': 2.7.11 + '@lmdb/lmdb-darwin-x64': 2.7.11 + '@lmdb/lmdb-linux-arm': 2.7.11 + '@lmdb/lmdb-linux-arm64': 2.7.11 + '@lmdb/lmdb-linux-x64': 2.7.11 + '@lmdb/lmdb-win32-x64': 2.7.11 + dev: false + + /load-tsconfig@0.2.5: + resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: false + + /locate-character@3.0.0: + resolution: {integrity: sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==} + dev: false + + /locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + dependencies: + p-locate: 5.0.0 + + /lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + /lodash.sortby@4.7.0: + resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==} + dev: false + + /lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + dev: false + + /log-symbols@4.1.0: + resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} + engines: {node: '>=10'} + dependencies: + chalk: 4.1.2 + is-unicode-supported: 0.1.0 + dev: false + + /loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + dependencies: + js-tokens: 4.0.0 + dev: false + + /lowercase-keys@3.0.0: + resolution: {integrity: sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: false + + /lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + + /lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + dependencies: + yallist: 3.1.1 + + /lru-cache@6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} + dependencies: + yallist: 4.0.0 + dev: false + + /lucide-react@0.407.0(react@18.3.1): + resolution: {integrity: sha512-+dRIu9Sry+E8wPF9+sY5eKld2omrU4X5IKXxrgqBt+o11IIHVU0QOfNoVWFuj0ZRDrxr4Wci26o2mKZqLGE0lA==} + peerDependencies: + react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 + dependencies: + react: 18.3.1 + dev: false + + /magic-string@0.30.11: + resolution: {integrity: sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==} + dependencies: + '@jridgewell/sourcemap-codec': 1.5.0 + dev: false + + /make-dir@2.1.0: + resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==} + engines: {node: '>=6'} + requiresBuild: true + dependencies: + pify: 4.0.1 + semver: 5.7.2 + dev: false + optional: true + + /mdn-data@2.0.14: + resolution: {integrity: sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==} + dev: false + + /mdn-data@2.0.30: + resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==} + dev: false + + /merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + dev: false + + /merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + /micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + + /mime@1.6.0: + resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} + engines: {node: '>=4'} + hasBin: true + requiresBuild: true + dev: false + optional: true + + /mime@2.6.0: + resolution: {integrity: sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==} + engines: {node: '>=4.0.0'} + hasBin: true + dev: false + + /mimic-fn@2.1.0: + resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} + engines: {node: '>=6'} + dev: false + + /mimic-response@3.1.0: + resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} + engines: {node: '>=10'} + dev: false + + /mimic-response@4.0.0: + resolution: {integrity: sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: false + + /minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + dependencies: + brace-expansion: 1.1.11 + + /minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + dependencies: + brace-expansion: 2.0.1 + + /minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + /minipass@7.1.2: + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + engines: {node: '>=16 || 14 >=14.17'} + + /mkdirp-classic@0.5.3: + resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} + dev: false + + /mnemonic-id@3.2.7: + resolution: {integrity: sha512-kysx9gAGbvrzuFYxKkcRjnsg/NK61ovJOV4F1cHTRl9T5leg+bo6WI0pWIvOFh1Z/yDL0cjA5R3EEGPPLDv/XA==} + dev: false + + /ms@2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + + /ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + dev: false + + /msgpackr-extract@3.0.3: + resolution: {integrity: sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA==} + hasBin: true + requiresBuild: true + dependencies: + node-gyp-build-optional-packages: 5.2.2 + optionalDependencies: + '@msgpackr-extract/msgpackr-extract-darwin-arm64': 3.0.3 + '@msgpackr-extract/msgpackr-extract-darwin-x64': 3.0.3 + '@msgpackr-extract/msgpackr-extract-linux-arm': 3.0.3 + '@msgpackr-extract/msgpackr-extract-linux-arm64': 3.0.3 + '@msgpackr-extract/msgpackr-extract-linux-x64': 3.0.3 + '@msgpackr-extract/msgpackr-extract-win32-x64': 3.0.3 + dev: false + optional: true + + /msgpackr@1.11.0: + resolution: {integrity: sha512-I8qXuuALqJe5laEBYoFykChhSXLikZmUhccjGsPuSJ/7uPip2TJ7lwdIQwWSAi0jGZDXv4WOP8Qg65QZRuXxXw==} + optionalDependencies: + msgpackr-extract: 3.0.3 + dev: false + + /msgpackr@1.8.5: + resolution: {integrity: sha512-mpPs3qqTug6ahbblkThoUY2DQdNXcm4IapwOS3Vm/87vmpzLVelvp9h3It1y9l1VPpiFLV11vfOXnmeEwiIXwg==} + optionalDependencies: + msgpackr-extract: 3.0.3 + dev: false + + /mute-stream@1.0.0: + resolution: {integrity: sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dev: false + + /mz@2.7.0: + resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + dependencies: + any-promise: 1.3.0 + object-assign: 4.1.1 + thenify-all: 1.6.0 + + /nanoid@3.3.7: + resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + /napi-build-utils@1.0.2: + resolution: {integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==} + dev: false + + /narrowing@1.5.0: + resolution: {integrity: sha512-DUu4XdKgkfAPTAL28k79pdnshDE2W5T24QAnidSPo2F/W1TX6CjNzmEeXQfE5O1lxQvC0GYI6ZRDsLcyzugEYA==} + dev: true + + /natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + /needle@3.3.1: + resolution: {integrity: sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==} + engines: {node: '>= 4.4.x'} + hasBin: true + requiresBuild: true + dependencies: + iconv-lite: 0.6.3 + sax: 1.4.1 + dev: false + optional: true + + /node-abi@3.67.0: + resolution: {integrity: sha512-bLn/fU/ALVBE9wj+p4Y21ZJWYFjUXLXPi/IewyLZkx3ApxKDNBWCKdReeKOtD8dWpOdDCeMyLh6ZewzcLsG2Nw==} + engines: {node: '>=10'} + dependencies: + semver: 7.5.4 + dev: false + + /node-addon-api@4.3.0: + resolution: {integrity: sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==} + dev: false + + /node-addon-api@6.1.0: + resolution: {integrity: sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==} + dev: false + + /node-addon-api@7.1.1: + resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} + dev: false + + /node-gyp-build-optional-packages@5.0.3: + resolution: {integrity: sha512-k75jcVzk5wnnc/FMxsf4udAoTEUv2jY3ycfdSd3yWu6Cnd1oee6/CfZJApyscA4FJOmdoixWwiwOyf16RzD5JA==} + hasBin: true + dev: false + + /node-gyp-build-optional-packages@5.0.6: + resolution: {integrity: sha512-2ZJErHG4du9G3/8IWl/l9Bp5BBFy63rno5GVmjQijvTuUZKsl6g8RB4KH/x3NLcV5ZBb4GsXmAuTYr6dRml3Gw==} + hasBin: true + dev: false + + /node-gyp-build-optional-packages@5.2.2: + resolution: {integrity: sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==} + hasBin: true + requiresBuild: true + dependencies: + detect-libc: 2.0.3 + dev: false + optional: true + + /node-object-hash@3.0.0: + resolution: {integrity: sha512-jLF6tlyletktvSAawuPmH1SReP0YfZQ+tBrDiTCK+Ai7eXPMS9odi5xW/iKC7ZhrWJJ0Z5xYcW/x+1fVMn1Qvw==} + engines: {node: '>=16', pnpm: '>=8'} + dev: false + + /node-releases@2.0.18: + resolution: {integrity: sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==} + + /normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + /normalize-range@0.1.2: + resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} + engines: {node: '>=0.10.0'} + dev: true + + /normalize-url@8.0.1: + resolution: {integrity: sha512-IO9QvjUMWxPQQhs60oOu10CRkWCiZzSUkzbXGGV9pviYl1fXYcvkzQ5jV9z8Y6un8ARoVRl4EtC6v6jNqbaJ/w==} + engines: {node: '>=14.16'} + dev: false + + /npm-run-path@4.0.1: + resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} + engines: {node: '>=8'} + dependencies: + path-key: 3.1.1 + dev: false + + /nth-check@2.1.1: + resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + dependencies: + boolbase: 1.0.0 + dev: false + + /nullthrows@1.1.1: + resolution: {integrity: sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==} + dev: false + + /object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + /object-hash@3.0.0: + resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} + engines: {node: '>= 6'} + + /object-inspect@1.13.2: + resolution: {integrity: sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==} + engines: {node: '>= 0.4'} + dev: false + + /object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + dev: false + + /object.assign@4.1.5: + resolution: {integrity: sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + has-symbols: 1.0.3 + object-keys: 1.1.1 + dev: false + + /object.entries@1.1.8: + resolution: {integrity: sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-object-atoms: 1.0.0 + dev: false + + /object.fromentries@2.0.8: + resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-object-atoms: 1.0.0 + dev: false + + /object.groupby@1.0.3: + resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + dev: false + + /object.values@1.2.0: + resolution: {integrity: sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-object-atoms: 1.0.0 + dev: false + + /once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + dependencies: + wrappy: 1.0.2 + + /onetime@5.1.2: + resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} + engines: {node: '>=6'} + dependencies: + mimic-fn: 2.1.0 + dev: false + + /optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + + /ora@5.4.1: + resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==} + engines: {node: '>=10'} + dependencies: + bl: 4.1.0 + chalk: 4.1.2 + cli-cursor: 3.1.0 + cli-spinners: 2.9.2 + is-interactive: 1.0.0 + is-unicode-supported: 0.1.0 + log-symbols: 4.1.0 + strip-ansi: 6.0.1 + wcwidth: 1.0.1 + dev: false + + /ordered-binary@1.5.1: + resolution: {integrity: sha512-5VyHfHY3cd0iza71JepYG50My+YUbrFtGoUz2ooEydPyPM7Aai/JW098juLr+RG6+rDJuzNNTsEQu2DZa1A41A==} + dev: false + + /os-tmpdir@1.0.2: + resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} + engines: {node: '>=0.10.0'} + dev: false + + /p-cancelable@3.0.0: + resolution: {integrity: sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==} + engines: {node: '>=12.20'} + dev: false + + /p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + dependencies: + yocto-queue: 0.1.0 + + /p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + dependencies: + p-limit: 3.1.0 + + /package-json-from-dist@1.0.0: + resolution: {integrity: sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==} + + /package-json@8.1.1: + resolution: {integrity: sha512-cbH9IAIJHNj9uXi196JVsRlt7cHKak6u/e6AkL/bkRelZ7rlL3X1YKxsZwa36xipOEKAsdtmaG6aAJoM1fx2zA==} + engines: {node: '>=14.16'} + dependencies: + got: 12.6.1 + registry-auth-token: 5.0.2 + registry-url: 6.0.1 + semver: 7.5.4 + dev: false + + /parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + dependencies: + callsites: 3.1.0 + + /parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + dependencies: + '@babel/code-frame': 7.24.7 + error-ex: 1.3.2 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + dev: false + + /parse-node-version@1.0.1: + resolution: {integrity: sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==} + engines: {node: '>= 0.10'} + dev: false + + /path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + /path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + + /path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + /path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + /path-scurry@1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} + dependencies: + lru-cache: 10.4.3 + minipass: 7.1.2 + + /path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + + /periscopic@3.1.0: + resolution: {integrity: sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==} + dependencies: + '@types/estree': 1.0.5 + estree-walker: 3.0.3 + is-reference: 3.0.2 + dev: false + + /picocolors@1.1.0: + resolution: {integrity: sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==} + + /picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + /pify@2.3.0: + resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} + engines: {node: '>=0.10.0'} + + /pify@4.0.1: + resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} + engines: {node: '>=6'} + requiresBuild: true + dev: false + optional: true + + /pirates@4.0.6: + resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} + engines: {node: '>= 6'} + + /plasmo@0.88.0(postcss@8.4.45)(react-dom@18.3.1)(react@18.3.1): + resolution: {integrity: sha512-pL0xA9Y4zZuqQTyOwt0rQ8cahFMZI9toGMCa3aosB3dtzRztSe2rm3LA8hS52UdvnAUXm2A4ecmTlweaGN69Uw==} + hasBin: true + dependencies: + '@expo/spawn-async': 1.7.2 + '@parcel/core': 2.9.3 + '@parcel/fs': 2.9.3(@parcel/core@2.9.3) + '@parcel/package-manager': 2.9.3(@parcel/core@2.9.3) + '@parcel/watcher': 2.2.0 + '@plasmohq/init': 0.7.0 + '@plasmohq/parcel-config': 0.41.0(postcss@8.4.45)(react-dom@18.3.1)(react@18.3.1)(typescript@5.2.2) + '@plasmohq/parcel-core': 0.1.8 + buffer: 6.0.3 + chalk: 5.3.0 + change-case: 5.1.2 + dotenv: 16.3.1 + dotenv-expand: 10.0.0 + events: 3.3.0 + fast-glob: 3.3.2 + fflate: 0.8.1 + get-port: 7.0.0 + got: 13.0.0 + ignore: 5.2.4 + inquirer: 9.2.12 + is-path-inside: 4.0.0 + json5: 2.2.3 + mnemonic-id: 3.2.7 + node-object-hash: 3.0.0 + package-json: 8.1.1 + process: 0.11.10 + semver: 7.5.4 + sharp: 0.32.6 + tempy: 3.1.0 + typescript: 5.2.2 + transitivePeerDependencies: + - '@swc/core' + - '@swc/helpers' + - arc-templates + - atpl + - babel-core + - bracket-template + - coffeescript + - cssnano + - dot + - eco + - ect + - ejs + - haml-coffee + - hamlet + - hamljs + - handlebars + - hogan.js + - htmling + - jazz + - jqtpl + - just + - liquid + - liquor + - lodash + - marko + - mote + - mustache + - nunjucks + - plates + - postcss + - pug + - purgecss + - qejs + - ractive + - razor-tmpl + - react + - react-dom + - relateurl + - slm + - squirrelly + - srcset + - supports-color + - teacup + - templayed + - terser + - then-pug + - tinyliquid + - toffee + - ts-node + - twig + - twing + - uncss + - underscore + - vash + - velocityjs + - walrus + - whiskers + dev: false + + /possible-typed-array-names@1.0.0: + resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} + engines: {node: '>= 0.4'} + dev: false + + /postcss-import@15.1.0(postcss@8.4.45): + resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} + engines: {node: '>=14.0.0'} + peerDependencies: + postcss: ^8.0.0 + dependencies: + postcss: 8.4.45 + postcss-value-parser: 4.2.0 + read-cache: 1.0.0 + resolve: 1.22.8 + + /postcss-js@4.0.1(postcss@8.4.45): + resolution: {integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==} + engines: {node: ^12 || ^14 || >= 16} + peerDependencies: + postcss: ^8.4.21 + dependencies: + camelcase-css: 2.0.1 + postcss: 8.4.45 + + /postcss-load-config@4.0.2(postcss@8.4.45): + resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==} + engines: {node: '>= 14'} + peerDependencies: + postcss: '>=8.0.9' + ts-node: '>=9.0.0' + peerDependenciesMeta: + postcss: + optional: true + ts-node: + optional: true + dependencies: + lilconfig: 3.1.2 + postcss: 8.4.45 + yaml: 2.5.1 + + /postcss-nested@6.2.0(postcss@8.4.45): + resolution: {integrity: sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==} + engines: {node: '>=12.0'} + peerDependencies: + postcss: ^8.2.14 + dependencies: + postcss: 8.4.45 + postcss-selector-parser: 6.1.2 + + /postcss-selector-parser@6.1.2: + resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==} + engines: {node: '>=4'} + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + + /postcss-value-parser@4.2.0: + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + + /postcss@8.4.45: + resolution: {integrity: sha512-7KTLTdzdZZYscUc65XmjFiB73vBhBfbPztCYdUNvlaso9PrzjzcmjqBPR0lNGkcVlcO4BjiO5rK/qNz+XAen1Q==} + engines: {node: ^10 || ^12 || >=14} + dependencies: + nanoid: 3.3.7 + picocolors: 1.1.0 + source-map-js: 1.2.0 + + /posthtml-parser@0.10.2: + resolution: {integrity: sha512-PId6zZ/2lyJi9LiKfe+i2xv57oEjJgWbsHGGANwos5AvdQp98i6AtamAl8gzSVFGfQ43Glb5D614cvZf012VKg==} + engines: {node: '>=12'} + dependencies: + htmlparser2: 7.2.0 + dev: false + + /posthtml-parser@0.11.0: + resolution: {integrity: sha512-QecJtfLekJbWVo/dMAA+OSwY79wpRmbqS5TeXvXSX+f0c6pW4/SE6inzZ2qkU7oAMCPqIDkZDvd/bQsSFUnKyw==} + engines: {node: '>=12'} + dependencies: + htmlparser2: 7.2.0 + dev: false + + /posthtml-render@3.0.0: + resolution: {integrity: sha512-z+16RoxK3fUPgwaIgH9NGnK1HKY9XIDpydky5eQGgAFVXTCSezalv9U2jQuNV+Z9qV1fDWNzldcw4eK0SSbqKA==} + engines: {node: '>=12'} + dependencies: + is-json: 2.0.1 + dev: false + + /posthtml@0.16.6: + resolution: {integrity: sha512-JcEmHlyLK/o0uGAlj65vgg+7LIms0xKXe60lcDOTU7oVX/3LuEuLwrQpW3VJ7de5TaFKiW4kWkaIpJL42FEgxQ==} + engines: {node: '>=12.0.0'} + dependencies: + posthtml-parser: 0.11.0 + posthtml-render: 3.0.0 + dev: false + + /prebuild-install@7.1.2: + resolution: {integrity: sha512-UnNke3IQb6sgarcZIDU3gbMeTp/9SSU1DAIkil7PrqG1vZlBtY5msYccSKSHDqa3hNg436IXK+SNImReuA1wEQ==} + engines: {node: '>=10'} + hasBin: true + dependencies: + detect-libc: 2.0.3 + expand-template: 2.0.3 + github-from-package: 0.0.0 + minimist: 1.2.8 + mkdirp-classic: 0.5.3 + napi-build-utils: 1.0.2 + node-abi: 3.67.0 + pump: 3.0.0 + rc: 1.2.8 + simple-get: 4.0.1 + tar-fs: 2.1.1 + tunnel-agent: 0.6.0 + dev: false + + /prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + /process@0.11.10: + resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} + engines: {node: '>= 0.6.0'} + dev: false + + /prop-types@15.8.1: + resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + dependencies: + loose-envify: 1.4.0 + object-assign: 4.1.1 + react-is: 16.13.1 + dev: false + + /proto-list@1.2.4: + resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} + dev: false + + /prr@1.0.1: + resolution: {integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==} + requiresBuild: true + dev: false + optional: true + + /pump@3.0.0: + resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==} + dependencies: + end-of-stream: 1.4.4 + once: 1.4.0 + dev: false + + /punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + /queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + /queue-tick@1.0.1: + resolution: {integrity: sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==} + dev: false + + /quick-lru@5.1.1: + resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} + engines: {node: '>=10'} + dev: false + + /rc@1.2.8: + resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} + hasBin: true + dependencies: + deep-extend: 0.6.0 + ini: 1.3.8 + minimist: 1.2.8 + strip-json-comments: 2.0.1 + dev: false + + /react-dom@18.3.1(react@18.3.1): + resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==} + peerDependencies: + react: ^18.3.1 + dependencies: + loose-envify: 1.4.0 + react: 18.3.1 + scheduler: 0.23.2 + dev: false + + /react-error-overlay@6.0.9: + resolution: {integrity: sha512-nQTTcUu+ATDbrSD1BZHr5kgSD4oF8OFjxun8uAaL8RwPBacGBNPf/yAuVVdx17N8XNzRDMrZ9XcKZHCjPW+9ew==} + dev: false + + /react-hook-form@7.53.0(react@18.3.1): + resolution: {integrity: sha512-M1n3HhqCww6S2hxLxciEXy2oISPnAzxY7gvwVPrtlczTM/1dDadXgUxDpHMrMTblDOcm/AXtXxHwZ3jpg1mqKQ==} + engines: {node: '>=18.0.0'} + peerDependencies: + react: ^16.8.0 || ^17 || ^18 || ^19 + dependencies: + react: 18.3.1 + dev: false + + /react-is@16.13.1: + resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + dev: false + + /react-refresh@0.14.0: + resolution: {integrity: sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==} + engines: {node: '>=0.10.0'} + dev: false + + /react-refresh@0.14.2: + resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==} + engines: {node: '>=0.10.0'} + dev: true + + /react-refresh@0.9.0: + resolution: {integrity: sha512-Gvzk7OZpiqKSkxsQvO/mbTN1poglhmAV7gR/DdIrRrSMXraRQQlfikRJOr3Nb9GTMPC5kof948Zy6jJZIFtDvQ==} + engines: {node: '>=0.10.0'} + dev: false + + /react-remove-scroll-bar@2.3.6(@types/react@18.3.5)(react@18.3.1): + resolution: {integrity: sha512-DtSYaao4mBmX+HDo5YWYdBWQwYIQQshUV/dVxFxK+KM26Wjwp1gZ6rv6OC3oujI6Bfu6Xyg3TwK533AQutsn/g==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 18.3.5 + react: 18.3.1 + react-style-singleton: 2.2.1(@types/react@18.3.5)(react@18.3.1) + tslib: 2.7.0 + dev: false + + /react-remove-scroll@2.5.7(@types/react@18.3.5)(react@18.3.1): + resolution: {integrity: sha512-FnrTWO4L7/Bhhf3CYBNArEG/yROV0tKmTv7/3h9QCFvH6sndeFf1wPqOcbFVu5VAulS5dV1wGT3GZZ/1GawqiA==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 18.3.5 + react: 18.3.1 + react-remove-scroll-bar: 2.3.6(@types/react@18.3.5)(react@18.3.1) + react-style-singleton: 2.2.1(@types/react@18.3.5)(react@18.3.1) + tslib: 2.7.0 + use-callback-ref: 1.3.2(@types/react@18.3.5)(react@18.3.1) + use-sidecar: 1.1.2(@types/react@18.3.5)(react@18.3.1) + dev: false + + /react-style-singleton@2.2.1(@types/react@18.3.5)(react@18.3.1): + resolution: {integrity: sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 18.3.5 + get-nonce: 1.0.1 + invariant: 2.2.4 + react: 18.3.1 + tslib: 2.7.0 + dev: false + + /react@18.3.1: + resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} + engines: {node: '>=0.10.0'} + dependencies: + loose-envify: 1.4.0 + dev: false + + /read-cache@1.0.0: + resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} + dependencies: + pify: 2.3.0 + + /readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + dev: false + + /readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + dependencies: + picomatch: 2.3.1 + + /reflect.getprototypeof@1.0.6: + resolution: {integrity: sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-errors: 1.3.0 + get-intrinsic: 1.2.4 + globalthis: 1.0.4 + which-builtin-type: 1.1.4 + dev: false + + /regenerator-runtime@0.13.11: + resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} + dev: false + + /regenerator-runtime@0.14.1: + resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} + dev: false + + /regexp.prototype.flags@1.5.2: + resolution: {integrity: sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-errors: 1.3.0 + set-function-name: 2.0.2 + dev: false + + /registry-auth-token@5.0.2: + resolution: {integrity: sha512-o/3ikDxtXaA59BmZuZrJZDJv8NMDGSj+6j6XaeBmHw8eY1i1qd9+6H+LjVvQXx3HN6aRCGa1cUdJ9RaJZUugnQ==} + engines: {node: '>=14'} + dependencies: + '@pnpm/npm-conf': 2.3.1 + dev: false + + /registry-url@6.0.1: + resolution: {integrity: sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q==} + engines: {node: '>=12'} + dependencies: + rc: 1.2.8 + dev: false + + /resolve-alpn@1.2.1: + resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==} + dev: false + + /resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + /resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + dev: false + + /resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + dev: true + + /resolve@1.22.8: + resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} + hasBin: true + dependencies: + is-core-module: 2.15.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + /resolve@2.0.0-next.5: + resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==} + hasBin: true + dependencies: + is-core-module: 2.15.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + dev: false + + /responselike@3.0.0: + resolution: {integrity: sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==} + engines: {node: '>=14.16'} + dependencies: + lowercase-keys: 3.0.0 + dev: false + + /restore-cursor@3.1.0: + resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} + engines: {node: '>=8'} + dependencies: + onetime: 5.1.2 + signal-exit: 3.0.7 + dev: false + + /reusify@1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + /rimraf@3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + deprecated: Rimraf versions prior to v4 are no longer supported + hasBin: true + dependencies: + glob: 7.2.3 + + /rollup@3.29.4: + resolution: {integrity: sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==} + engines: {node: '>=14.18.0', npm: '>=8.0.0'} + hasBin: true + optionalDependencies: + fsevents: 2.3.3 + dev: false + + /rollup@4.21.2: + resolution: {integrity: sha512-e3TapAgYf9xjdLvKQCkQTnbTKd4a6jwlpQSJJFokHGaX2IVjoEqkIIhiQfqsi0cdwlOD+tQGuOd5AJkc5RngBw==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + dependencies: + '@types/estree': 1.0.5 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.21.2 + '@rollup/rollup-android-arm64': 4.21.2 + '@rollup/rollup-darwin-arm64': 4.21.2 + '@rollup/rollup-darwin-x64': 4.21.2 + '@rollup/rollup-linux-arm-gnueabihf': 4.21.2 + '@rollup/rollup-linux-arm-musleabihf': 4.21.2 + '@rollup/rollup-linux-arm64-gnu': 4.21.2 + '@rollup/rollup-linux-arm64-musl': 4.21.2 + '@rollup/rollup-linux-powerpc64le-gnu': 4.21.2 + '@rollup/rollup-linux-riscv64-gnu': 4.21.2 + '@rollup/rollup-linux-s390x-gnu': 4.21.2 + '@rollup/rollup-linux-x64-gnu': 4.21.2 + '@rollup/rollup-linux-x64-musl': 4.21.2 + '@rollup/rollup-win32-arm64-msvc': 4.21.2 + '@rollup/rollup-win32-ia32-msvc': 4.21.2 + '@rollup/rollup-win32-x64-msvc': 4.21.2 + fsevents: 2.3.3 + dev: true + + /run-async@3.0.0: + resolution: {integrity: sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==} + engines: {node: '>=0.12.0'} + dev: false + + /run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + dependencies: + queue-microtask: 1.2.3 + + /rxjs@7.8.1: + resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==} + dependencies: + tslib: 2.7.0 + dev: false + + /safe-array-concat@1.1.2: + resolution: {integrity: sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==} + engines: {node: '>=0.4'} + dependencies: + call-bind: 1.0.7 + get-intrinsic: 1.2.4 + has-symbols: 1.0.3 + isarray: 2.0.5 + dev: false + + /safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + dev: false + + /safe-regex-test@1.0.3: + resolution: {integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-regex: 1.1.4 + dev: false + + /safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + dev: false + + /sass@1.78.0: + resolution: {integrity: sha512-AaIqGSrjo5lA2Yg7RvFZrlXDBCp3nV4XP73GrLGvdRWWwk+8H3l0SDvq/5bA4eF+0RFPLuWUk3E+P1U/YqnpsQ==} + engines: {node: '>=14.0.0'} + hasBin: true + dependencies: + chokidar: 3.6.0 + immutable: 4.3.7 + source-map-js: 1.2.0 + dev: false + + /sax@1.4.1: + resolution: {integrity: sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==} + requiresBuild: true + dev: false + optional: true + + /scheduler@0.23.2: + resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} + dependencies: + loose-envify: 1.4.0 + dev: false + + /semver@5.7.2: + resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} + hasBin: true + dev: false + + /semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + /semver@7.5.4: + resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} + engines: {node: '>=10'} + hasBin: true + dependencies: + lru-cache: 6.0.0 + dev: false + + /semver@7.6.3: + resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} + engines: {node: '>=10'} + hasBin: true + + /set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.2.4 + gopd: 1.0.1 + has-property-descriptors: 1.0.2 + dev: false + + /set-function-name@2.0.2: + resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} + engines: {node: '>= 0.4'} + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + functions-have-names: 1.2.3 + has-property-descriptors: 1.0.2 + dev: false + + /sharp@0.32.6: + resolution: {integrity: sha512-KyLTWwgcR9Oe4d9HwCwNM2l7+J0dUQwn/yf7S0EnTtb0eVS4RxO0eUSvxPtzT4F3SY+C4K6fqdv/DO27sJ/v/w==} + engines: {node: '>=14.15.0'} + requiresBuild: true + dependencies: + color: 4.2.3 + detect-libc: 2.0.3 + node-addon-api: 6.1.0 + prebuild-install: 7.1.2 + semver: 7.5.4 + simple-get: 4.0.1 + tar-fs: 3.0.6 + tunnel-agent: 0.6.0 + dev: false + + /shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + dependencies: + shebang-regex: 3.0.0 + + /shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + /side-channel@1.0.6: + resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + get-intrinsic: 1.2.4 + object-inspect: 1.13.2 + dev: false + + /signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + dev: false + + /signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + + /simple-concat@1.0.1: + resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==} + dev: false + + /simple-get@4.0.1: + resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==} + dependencies: + decompress-response: 6.0.0 + once: 1.4.0 + simple-concat: 1.0.1 + dev: false + + /simple-swizzle@0.2.2: + resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==} + dependencies: + is-arrayish: 0.3.2 + dev: false + + /slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + + /source-map-js@1.2.0: + resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==} + engines: {node: '>=0.10.0'} + + /source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + dev: false + + /source-map@0.8.0-beta.0: + resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} + engines: {node: '>= 8'} + dependencies: + whatwg-url: 7.1.0 + dev: false + + /srcset@4.0.0: + resolution: {integrity: sha512-wvLeHgcVHKO8Sc/H/5lkGreJQVeYMm9rlmt8PuR1xE31rIuXhuzznUUqAt8MqLhB3MqJdFzlNAfpcWnxiFUcPw==} + engines: {node: '>=12'} + dev: false + + /stable@0.1.8: + resolution: {integrity: sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==} + deprecated: 'Modern JS already guarantees Array#sort() is a stable sort, so this library is deprecated. See the compatibility table on MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#browser_compatibility' + dev: false + + /streamx@2.20.0: + resolution: {integrity: sha512-ZGd1LhDeGFucr1CUCTBOS58ZhEendd0ttpGT3usTvosS4ntIwKN9LJFp+OeCSprsCPL14BXVRZlHGRY1V9PVzQ==} + dependencies: + fast-fifo: 1.3.2 + queue-tick: 1.0.1 + text-decoder: 1.1.1 + optionalDependencies: + bare-events: 2.4.2 + dev: false + + /string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + /string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.1.0 + + /string.prototype.matchall@4.0.11: + resolution: {integrity: sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + get-intrinsic: 1.2.4 + gopd: 1.0.1 + has-symbols: 1.0.3 + internal-slot: 1.0.7 + regexp.prototype.flags: 1.5.2 + set-function-name: 2.0.2 + side-channel: 1.0.6 + dev: false + + /string.prototype.repeat@1.0.0: + resolution: {integrity: sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==} + dependencies: + define-properties: 1.2.1 + es-abstract: 1.23.3 + dev: false + + /string.prototype.trim@1.2.9: + resolution: {integrity: sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-object-atoms: 1.0.0 + dev: false + + /string.prototype.trimend@1.0.8: + resolution: {integrity: sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-object-atoms: 1.0.0 + dev: false + + /string.prototype.trimstart@1.0.8: + resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-object-atoms: 1.0.0 + dev: false + + /string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + dependencies: + safe-buffer: 5.2.1 + dev: false + + /strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + dependencies: + ansi-regex: 5.0.1 + + /strip-ansi@7.1.0: + resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} + engines: {node: '>=12'} + dependencies: + ansi-regex: 6.0.1 + + /strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + + /strip-final-newline@2.0.0: + resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} + engines: {node: '>=6'} + dev: false + + /strip-json-comments@2.0.1: + resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} + engines: {node: '>=0.10.0'} + dev: false + + /strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + /sucrase@3.35.0: + resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true + dependencies: + '@jridgewell/gen-mapping': 0.3.5 + commander: 4.1.1 + glob: 10.4.5 + lines-and-columns: 1.2.4 + mz: 2.7.0 + pirates: 4.0.6 + ts-interface-checker: 0.1.13 + + /supports-color@5.5.0: + resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} + engines: {node: '>=4'} + dependencies: + has-flag: 3.0.0 + + /supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + dependencies: + has-flag: 4.0.0 + + /supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + /svelte@4.2.2: + resolution: {integrity: sha512-My2tytF2e2NnHSpn2M7/3VdXT4JdTglYVUuSuK/mXL2XtulPYbeBfl8Dm1QiaKRn0zoULRnL+EtfZHHP0k4H3A==} + engines: {node: '>=16'} + dependencies: + '@ampproject/remapping': 2.3.0 + '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/trace-mapping': 0.3.25 + acorn: 8.12.1 + aria-query: 5.3.0 + axobject-query: 3.2.4 + code-red: 1.0.4 + css-tree: 2.3.1 + estree-walker: 3.0.3 + is-reference: 3.0.2 + locate-character: 3.0.0 + magic-string: 0.30.11 + periscopic: 3.1.0 + dev: false + + /svg-parser@2.0.4: + resolution: {integrity: sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==} + dev: false + + /svgo@2.8.0: + resolution: {integrity: sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==} + engines: {node: '>=10.13.0'} + hasBin: true + dependencies: + '@trysound/sax': 0.2.0 + commander: 7.2.0 + css-select: 4.3.0 + css-tree: 1.1.3 + csso: 4.2.0 + picocolors: 1.1.0 + stable: 0.1.8 + dev: false + + /tailwind-merge@2.5.2: + resolution: {integrity: sha512-kjEBm+pvD+6eAwzJL2Bi+02/9LFLal1Gs61+QB7HvTfQQ0aXwC5LGT8PEt1gS0CWKktKe6ysPTAy3cBC5MeiIg==} + dev: false + + /tailwindcss-animate@1.0.7(tailwindcss@3.4.10): + resolution: {integrity: sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==} + peerDependencies: + tailwindcss: '>=3.0.0 || insiders' + dependencies: + tailwindcss: 3.4.10 + dev: false + + /tailwindcss@3.4.10: + resolution: {integrity: sha512-KWZkVPm7yJRhdu4SRSl9d4AK2wM3a50UsvgHZO7xY77NQr2V+fIrEuoDGQcbvswWvFGbS2f6e+jC/6WJm1Dl0w==} + engines: {node: '>=14.0.0'} + hasBin: true + dependencies: + '@alloc/quick-lru': 5.2.0 + arg: 5.0.2 + chokidar: 3.6.0 + didyoumean: 1.2.2 + dlv: 1.1.3 + fast-glob: 3.3.2 + glob-parent: 6.0.2 + is-glob: 4.0.3 + jiti: 1.21.6 + lilconfig: 2.1.0 + micromatch: 4.0.8 + normalize-path: 3.0.0 + object-hash: 3.0.0 + picocolors: 1.1.0 + postcss: 8.4.45 + postcss-import: 15.1.0(postcss@8.4.45) + postcss-js: 4.0.1(postcss@8.4.45) + postcss-load-config: 4.0.2(postcss@8.4.45) + postcss-nested: 6.2.0(postcss@8.4.45) + postcss-selector-parser: 6.1.2 + resolve: 1.22.8 + sucrase: 3.35.0 + transitivePeerDependencies: + - ts-node + + /tar-fs@2.1.1: + resolution: {integrity: sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==} + dependencies: + chownr: 1.1.4 + mkdirp-classic: 0.5.3 + pump: 3.0.0 + tar-stream: 2.2.0 + dev: false + + /tar-fs@3.0.6: + resolution: {integrity: sha512-iokBDQQkUyeXhgPYaZxmczGPhnhXZ0CmrqI+MOb/WFGS9DW5wnfrLgtjUJBvz50vQ3qfRwJ62QVoCFu8mPVu5w==} + dependencies: + pump: 3.0.0 + tar-stream: 3.1.7 + optionalDependencies: + bare-fs: 2.3.3 + bare-path: 2.1.3 + dev: false + + /tar-stream@2.2.0: + resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} + engines: {node: '>=6'} + dependencies: + bl: 4.1.0 + end-of-stream: 1.4.4 + fs-constants: 1.0.0 + inherits: 2.0.4 + readable-stream: 3.6.2 + dev: false + + /tar-stream@3.1.7: + resolution: {integrity: sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==} + dependencies: + b4a: 1.6.6 + fast-fifo: 1.3.2 + streamx: 2.20.0 + dev: false + + /temp-dir@3.0.0: + resolution: {integrity: sha512-nHc6S/bwIilKHNRgK/3jlhDoIHcp45YgyiwcAk46Tr0LfEqGBVpmiAyuiuxeVE44m3mXnEeVhaipLOEWmH+Njw==} + engines: {node: '>=14.16'} + dev: false + + /tempy@3.1.0: + resolution: {integrity: sha512-7jDLIdD2Zp0bDe5r3D2qtkd1QOCacylBuL7oa4udvN6v2pqr4+LcCr67C8DR1zkpaZ8XosF5m1yQSabKAW6f2g==} + engines: {node: '>=14.16'} + dependencies: + is-stream: 3.0.0 + temp-dir: 3.0.0 + type-fest: 2.19.0 + unique-string: 3.0.0 + dev: false + + /text-decoder@1.1.1: + resolution: {integrity: sha512-8zll7REEv4GDD3x4/0pW+ppIxSNs7H1J10IKFZsuOMscumCdM2a+toDGLPA3T+1+fLBql4zbt5z83GEQGGV5VA==} + dependencies: + b4a: 1.6.6 + dev: false + + /text-table@0.2.0: + resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + + /thenify-all@1.6.0: + resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} + engines: {node: '>=0.8'} + dependencies: + thenify: 3.3.1 + + /thenify@3.3.1: + resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + dependencies: + any-promise: 1.3.0 + + /timsort@0.3.0: + resolution: {integrity: sha512-qsdtZH+vMoCARQtyod4imc2nIJwg9Cc7lPRrw9CzF8ZKR0khdr8+2nX80PBhET3tcyTtJDxAffGh2rXH4tyU8A==} + dev: false + + /tmp@0.0.33: + resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} + engines: {node: '>=0.6.0'} + dependencies: + os-tmpdir: 1.0.2 + dev: false + + /to-fast-properties@2.0.0: + resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} + engines: {node: '>=4'} + + /to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + dependencies: + is-number: 7.0.0 + + /tr46@1.0.1: + resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==} + dependencies: + punycode: 2.3.1 + dev: false + + /tree-kill@1.2.2: + resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} + hasBin: true + dev: false + + /ts-algebra@1.2.2: + resolution: {integrity: sha512-kloPhf1hq3JbCPOTYoOWDKxebWjNb2o/LKnNfkWhxVVisFFmMJPPdJeGoGmM+iRLyoXAR61e08Pb+vUXINg8aA==} + dev: false + + /ts-api-utils@1.3.0(typescript@5.5.4): + resolution: {integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==} + engines: {node: '>=16'} + peerDependencies: + typescript: '>=4.2.0' + dependencies: + typescript: 5.5.4 + + /ts-interface-checker@0.1.13: + resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + + /tsconfck@3.1.3(typescript@5.5.4): + resolution: {integrity: sha512-ulNZP1SVpRDesxeMLON/LtWM8HIgAJEIVpVVhBM6gsmvQ8+Rh+ZG7FWGvHh7Ah3pRABwVJWklWCr/BTZSv0xnQ==} + engines: {node: ^18 || >=20} + hasBin: true + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + dependencies: + typescript: 5.5.4 + dev: true + + /tsconfig-paths@3.15.0: + resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} + dependencies: + '@types/json5': 0.0.29 + json5: 1.0.2 + minimist: 1.2.8 + strip-bom: 3.0.0 + dev: false + + /tsconfig-paths@4.2.0: + resolution: {integrity: sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==} + engines: {node: '>=6'} + dependencies: + json5: 2.2.3 + minimist: 1.2.8 + strip-bom: 3.0.0 + dev: true + + /tslib@2.7.0: + resolution: {integrity: sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==} + dev: false + + /tsup@7.2.0(postcss@8.4.45)(typescript@5.2.2): + resolution: {integrity: sha512-vDHlczXbgUvY3rWvqFEbSqmC1L7woozbzngMqTtL2PGBODTtWlRwGDDawhvWzr5c1QjKe4OAKqJGfE1xeXUvtQ==} + engines: {node: '>=16.14'} + hasBin: true + peerDependencies: + '@swc/core': ^1 + postcss: ^8.4.12 + typescript: '>=4.1.0' + peerDependenciesMeta: + '@swc/core': + optional: true + postcss: + optional: true + typescript: + optional: true + dependencies: + bundle-require: 4.2.1(esbuild@0.18.20) + cac: 6.7.14 + chokidar: 3.6.0 + debug: 4.3.6 + esbuild: 0.18.20 + execa: 5.1.1 + globby: 11.1.0 + joycon: 3.1.1 + postcss: 8.4.45 + postcss-load-config: 4.0.2(postcss@8.4.45) + resolve-from: 5.0.0 + rollup: 3.29.4 + source-map: 0.8.0-beta.0 + sucrase: 3.35.0 + tree-kill: 1.2.2 + typescript: 5.2.2 + transitivePeerDependencies: + - supports-color + - ts-node + dev: false + + /tsx@4.19.1: + resolution: {integrity: sha512-0flMz1lh74BR4wOvBjuh9olbnwqCPc35OOlfyzHba0Dc+QNUeWX/Gq2YTbnwcWPO3BMd8fkzRVrHcsR+a7z7rA==} + engines: {node: '>=18.0.0'} + hasBin: true + dependencies: + esbuild: 0.23.1 + get-tsconfig: 4.8.1 + optionalDependencies: + fsevents: 2.3.3 + dev: true + + /tunnel-agent@0.6.0: + resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} + dependencies: + safe-buffer: 5.2.1 + dev: false + + /type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + dependencies: + prelude-ls: 1.2.1 + + /type-fest@0.20.2: + resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} + engines: {node: '>=10'} + + /type-fest@0.21.3: + resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} + engines: {node: '>=10'} + dev: false + + /type-fest@1.4.0: + resolution: {integrity: sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==} + engines: {node: '>=10'} + dev: false + + /type-fest@2.19.0: + resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==} + engines: {node: '>=12.20'} + dev: false + + /typed-array-buffer@1.0.2: + resolution: {integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-typed-array: 1.1.13 + dev: false + + /typed-array-byte-length@1.0.1: + resolution: {integrity: sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + for-each: 0.3.3 + gopd: 1.0.1 + has-proto: 1.0.3 + is-typed-array: 1.1.13 + dev: false + + /typed-array-byte-offset@1.0.2: + resolution: {integrity: sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==} + engines: {node: '>= 0.4'} + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.7 + for-each: 0.3.3 + gopd: 1.0.1 + has-proto: 1.0.3 + is-typed-array: 1.1.13 + dev: false + + /typed-array-length@1.0.6: + resolution: {integrity: sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.7 + for-each: 0.3.3 + gopd: 1.0.1 + has-proto: 1.0.3 + is-typed-array: 1.1.13 + possible-typed-array-names: 1.0.0 + dev: false + + /typescript@5.2.2: + resolution: {integrity: sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==} + engines: {node: '>=14.17'} + hasBin: true + dev: false + + /typescript@5.5.4: + resolution: {integrity: sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==} + engines: {node: '>=14.17'} + hasBin: true + + /unbox-primitive@1.0.2: + resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} + dependencies: + call-bind: 1.0.7 + has-bigints: 1.0.2 + has-symbols: 1.0.3 + which-boxed-primitive: 1.0.2 + dev: false + + /undici-types@6.19.8: + resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} + dev: true + + /unique-string@3.0.0: + resolution: {integrity: sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ==} + engines: {node: '>=12'} + dependencies: + crypto-random-string: 4.0.0 + dev: false + + /universalify@2.0.1: + resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} + engines: {node: '>= 10.0.0'} + + /update-browserslist-db@1.1.0(browserslist@4.22.1): + resolution: {integrity: sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + dependencies: + browserslist: 4.22.1 + escalade: 3.2.0 + picocolors: 1.1.0 + dev: false + + /update-browserslist-db@1.1.0(browserslist@4.23.3): + resolution: {integrity: sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + dependencies: + browserslist: 4.23.3 + escalade: 3.2.0 + picocolors: 1.1.0 + + /uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + dependencies: + punycode: 2.3.1 + + /use-callback-ref@1.3.2(@types/react@18.3.5)(react@18.3.1): + resolution: {integrity: sha512-elOQwe6Q8gqZgDA8mrh44qRTQqpIHDcZ3hXTLjBe1i4ph8XpNJnO+aQf3NaG+lriLopI4HMx9VjQLfPQ6vhnoA==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 18.3.5 + react: 18.3.1 + tslib: 2.7.0 + dev: false + + /use-sidecar@1.1.2(@types/react@18.3.5)(react@18.3.1): + resolution: {integrity: sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': ^16.9.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 18.3.5 + detect-node-es: 1.1.0 + react: 18.3.1 + tslib: 2.7.0 + dev: false + + /util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + /utility-types@3.11.0: + resolution: {integrity: sha512-6Z7Ma2aVEWisaL6TvBCy7P8rm2LQoPv6dJ7ecIaIixHcwfbJ0x7mWdbcwlIM5IGQxPZSFYeqRCqlOOeKoJYMkw==} + engines: {node: '>= 4'} + dev: false + + /viem@2.21.1(typescript@5.5.4)(zod@3.23.8): + resolution: {integrity: sha512-nlIc2LLS6aqkngULS9UJ2Sg3nHKAgF9bbpDUwjUoAUBijd69mrCWPBXQ8jmbzcx12uZUfd9Nc//CHgSVZiMwyg==} + peerDependencies: + typescript: '>=5.0.4' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@adraffy/ens-normalize': 1.10.0 + '@noble/curves': 1.4.0 + '@noble/hashes': 1.4.0 + '@scure/bip32': 1.4.0 + '@scure/bip39': 1.3.0 + abitype: 1.0.5(typescript@5.5.4)(zod@3.23.8) + isows: 1.0.4(ws@8.17.1) + typescript: 5.5.4 + webauthn-p256: 0.0.5 + ws: 8.17.1 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + - zod + dev: false + + /vite-plugin-env-compatible@2.0.1: + resolution: {integrity: sha512-DRrOZTg/W44ojVQQfGSMPEgYQGzp5TeIpt9cpaK35hTOC/b2D7Ffl8/RIgK8vQ0mlnDIUgETcA173bnMEkyzdw==} + dependencies: + dotenv: 8.2.0 + dotenv-expand: 5.1.0 + dev: false + + /vite-plugin-static-copy@1.0.6(vite@5.4.3): + resolution: {integrity: sha512-3uSvsMwDVFZRitqoWHj0t4137Kz7UynnJeq1EZlRW7e25h2068fyIZX4ORCCOAkfp1FklGxJNVJBkBOD+PZIew==} + engines: {node: ^18.0.0 || >=20.0.0} + peerDependencies: + vite: ^5.0.0 + dependencies: + chokidar: 3.6.0 + fast-glob: 3.3.2 + fs-extra: 11.2.0 + picocolors: 1.1.0 + vite: 5.4.3(@types/node@20.16.4) + dev: true + + /vite-plugin-wasm-pack@0.1.12: + resolution: {integrity: sha512-WliYvQp9HXluir4OKGbngkcKxtYtifU11cqLurRRJGsl770Sjr1iIkp5RuvU3IC1poT4A57Z2/YgAKI2Skm7ZA==} + dependencies: + chalk: 4.1.2 + fs-extra: 10.1.0 + narrowing: 1.5.0 + dev: true + + /vite-tsconfig-paths@4.3.2(typescript@5.5.4)(vite@5.4.3): + resolution: {integrity: sha512-0Vd/a6po6Q+86rPlntHye7F31zA2URZMbH8M3saAZ/xR9QoGN/L21bxEGfXdWmFdNkqPpRdxFT7nmNe12e9/uA==} + peerDependencies: + vite: '*' + peerDependenciesMeta: + vite: + optional: true + dependencies: + debug: 4.3.6 + globrex: 0.1.2 + tsconfck: 3.1.3(typescript@5.5.4) + vite: 5.4.3(@types/node@20.16.4) + transitivePeerDependencies: + - supports-color + - typescript + dev: true + + /vite@5.4.3(@types/node@20.16.4): + resolution: {integrity: sha512-IH+nl64eq9lJjFqU+/yrRnrHPVTlgy42/+IzbOdaFDVlyLgI/wDlf+FCobXLX1cT0X5+7LMyH1mIy2xJdLfo8Q==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || >=20.0.0 + less: '*' + lightningcss: ^1.21.0 + sass: '*' + sass-embedded: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + dependencies: + '@types/node': 20.16.4 + esbuild: 0.21.5 + postcss: 8.4.45 + rollup: 4.21.2 + optionalDependencies: + fsevents: 2.3.3 + dev: true + + /vue@3.3.4: + resolution: {integrity: sha512-VTyEYn3yvIeY1Py0WaYGZsXnz3y5UnGi62GjVEqvEGPl6nxbOrCXbVOTQWBEJUqAyTUk2uJ5JLVnYJ6ZzGbrSw==} + dependencies: + '@vue/compiler-dom': 3.3.4 + '@vue/compiler-sfc': 3.3.4 + '@vue/runtime-dom': 3.3.4 + '@vue/server-renderer': 3.3.4(vue@3.3.4) + '@vue/shared': 3.3.4 + dev: false + + /wcwidth@1.0.1: + resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} + dependencies: + defaults: 1.0.4 + dev: false + + /weak-lru-cache@1.2.2: + resolution: {integrity: sha512-DEAoo25RfSYMuTGc9vPJzZcZullwIqRDSI9LOy+fkCJPi6hykCnfKaXTuPBDuXAUcqHXyOgFtHNp/kB2FjYHbw==} + dev: false + + /webauthn-p256@0.0.5: + resolution: {integrity: sha512-drMGNWKdaixZNobeORVIqq7k5DsRC9FnG201K2QjeOoQLmtSDaSsVZdkg6n5jUALJKcAG++zBPJXmv6hy0nWFg==} + dependencies: + '@noble/curves': 1.4.0 + '@noble/hashes': 1.4.0 + dev: false + + /webidl-conversions@4.0.2: + resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==} + dev: false + + /whatwg-url@7.1.0: + resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==} + dependencies: + lodash.sortby: 4.7.0 + tr46: 1.0.1 + webidl-conversions: 4.0.2 + dev: false + + /which-boxed-primitive@1.0.2: + resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} + dependencies: + is-bigint: 1.0.4 + is-boolean-object: 1.1.2 + is-number-object: 1.0.7 + is-string: 1.0.7 + is-symbol: 1.0.4 + dev: false + + /which-builtin-type@1.1.4: + resolution: {integrity: sha512-bppkmBSsHFmIMSl8BO9TbsyzsvGjVoppt8xUiGzwiu/bhDCGxnpOKCxgqj6GuyHE0mINMDecBFPlOm2hzY084w==} + engines: {node: '>= 0.4'} + dependencies: + function.prototype.name: 1.1.6 + has-tostringtag: 1.0.2 + is-async-function: 2.0.0 + is-date-object: 1.0.5 + is-finalizationregistry: 1.0.2 + is-generator-function: 1.0.10 + is-regex: 1.1.4 + is-weakref: 1.0.2 + isarray: 2.0.5 + which-boxed-primitive: 1.0.2 + which-collection: 1.0.2 + which-typed-array: 1.1.15 + dev: false + + /which-collection@1.0.2: + resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} + engines: {node: '>= 0.4'} + dependencies: + is-map: 2.0.3 + is-set: 2.0.3 + is-weakmap: 2.0.2 + is-weakset: 2.0.3 + dev: false + + /which-typed-array@1.1.15: + resolution: {integrity: sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==} + engines: {node: '>= 0.4'} + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.7 + for-each: 0.3.3 + gopd: 1.0.1 + has-tostringtag: 1.0.2 + dev: false + + /which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + dependencies: + isexe: 2.0.0 + + /word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + + /wrap-ansi@6.2.0: + resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} + engines: {node: '>=8'} + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + dev: false + + /wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + /wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + dependencies: + ansi-styles: 6.2.1 + string-width: 5.1.2 + strip-ansi: 7.1.0 + + /wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + /ws@8.17.1: + resolution: {integrity: sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + dev: false + + /xxhash-wasm@0.4.2: + resolution: {integrity: sha512-/eyHVRJQCirEkSZ1agRSCwriMhwlyUcFkXD5TPVSLP+IPzjsqMVzZwdoczLp1SoQU0R3dxz1RpIK+4YNQbCVOA==} + dev: false + + /yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + + /yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + dev: false + + /yaml@1.10.2: + resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} + engines: {node: '>= 6'} + dev: false + + /yaml@2.5.1: + resolution: {integrity: sha512-bLQOjaX/ADgQ20isPJRvF0iRUHIxVhYvr53Of7wGcWlO2jvtUlH5m87DsmulFVxRpNLOnI4tB6p/oh8D7kpn9Q==} + engines: {node: '>= 14'} + hasBin: true + + /yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + + /zod@3.23.8: + resolution: {integrity: sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==} + dev: false diff --git a/ts/browser-extension/postcss.config.js b/ts/browser-extension/postcss.config.js new file mode 100644 index 00000000..ba807304 --- /dev/null +++ b/ts/browser-extension/postcss.config.js @@ -0,0 +1,6 @@ +export default { + plugins: { + tailwindcss: {}, + autoprefixer: {} + } +}; diff --git a/ts/browser-extension/public/icon.png b/ts/browser-extension/public/icon.png new file mode 100644 index 00000000..8ff79757 Binary files /dev/null and b/ts/browser-extension/public/icon.png differ diff --git a/ts/browser-extension/src/App.tsx b/ts/browser-extension/src/App.tsx new file mode 100644 index 00000000..055a68ac --- /dev/null +++ b/ts/browser-extension/src/App.tsx @@ -0,0 +1,13 @@ +import { Providers } from './Providers'; + +import { Wallet } from '@/domains/wallet'; + +function App() { + return ( + + + + ); +} + +export default App; diff --git a/ts/browser-extension/src/Providers.tsx b/ts/browser-extension/src/Providers.tsx new file mode 100644 index 00000000..8e65d603 --- /dev/null +++ b/ts/browser-extension/src/Providers.tsx @@ -0,0 +1,21 @@ +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import type { ReactNode } from 'react'; + +import { WasmProvider } from './domains/shielder'; + +import { Toaster } from '@/components'; + +type Props = { children: ReactNode }; + +export const Providers = ({ children }: Props) => { + const queryClient = new QueryClient(); + + return ( + <> + + {children} + + + + ); +}; diff --git a/ts/browser-extension/src/background.ts b/ts/browser-extension/src/background.ts new file mode 100644 index 00000000..183aae63 --- /dev/null +++ b/ts/browser-extension/src/background.ts @@ -0,0 +1,5 @@ +export {}; + +chrome.sidePanel + .setPanelBehavior({ openPanelOnActionClick: true }) + .catch((error: unknown) => void console.error(error)); diff --git a/ts/browser-extension/src/components/Address.tsx b/ts/browser-extension/src/components/Address.tsx new file mode 100644 index 00000000..a9263c85 --- /dev/null +++ b/ts/browser-extension/src/components/Address.tsx @@ -0,0 +1,49 @@ +import { Check, Copy } from 'lucide-react'; +import { useState } from 'react'; + +import cn from '@/utils/classnames'; + +type Props = { + className?: string, + address: string, +}; + +const Address = (props: Props) => { + const [isCopied, setIsCopied] = useState(false); + + const truncateAddress = (addr: string) => { + if (addr.length > 13) { + return `${addr.slice(0, 5)}...${addr.slice(-5)}`; + } + return addr; + }; + + const copyAddress = (addr: string) => { + void navigator.clipboard.writeText(addr); + setIsCopied(true); + setTimeout(() => void setIsCopied(false), 2000); + }; + + return ( +
void copyAddress(props.address)} + > +
{truncateAddress(props.address)}
+
+ {isCopied ? ( + + ) : ( + + )} +
+
+ ); +}; + +export default Address; diff --git a/ts/browser-extension/src/components/Button.tsx b/ts/browser-extension/src/components/Button.tsx new file mode 100644 index 00000000..781e5b9c --- /dev/null +++ b/ts/browser-extension/src/components/Button.tsx @@ -0,0 +1,56 @@ +/* eslint-disable react-refresh/only-export-components */ +import { Slot } from '@radix-ui/react-slot'; +import { cva, type VariantProps } from 'class-variance-authority'; +import * as React from 'react'; + +import cn from '@/utils/classnames'; + +const buttonVariants = cva( + 'inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50', + { + variants: { + variant: { + default: 'bg-primary text-primary-foreground hover:bg-primary/90', + destructive: + 'bg-destructive text-destructive-foreground hover:bg-destructive/90', + outline: + 'border border-input bg-background hover:bg-accent hover:text-accent-foreground', + secondary: + 'bg-secondary text-secondary-foreground hover:bg-secondary/80', + ghost: 'hover:bg-accent hover:text-accent-foreground', + link: 'text-primary underline-offset-4 hover:underline', + }, + size: { + default: 'h-10 px-4 py-2', + sm: 'h-9 rounded-md px-3', + lg: 'h-11 rounded-md px-8', + icon: 'h-10 w-10', + }, + }, + defaultVariants: { + variant: 'default', + size: 'default', + }, + } +); + +type Props = { + asChild?: boolean, +} & React.ButtonHTMLAttributes & VariantProps; + +const Button = React.forwardRef( + ({ className, variant, size, asChild = false, ...props }, ref) => { + const Comp = asChild ? Slot : 'button'; + return ( + + ); + } +); +Button.displayName = 'Button'; + +export default Button; +export { buttonVariants }; diff --git a/ts/browser-extension/src/components/Card.tsx b/ts/browser-extension/src/components/Card.tsx new file mode 100644 index 00000000..ef2367f6 --- /dev/null +++ b/ts/browser-extension/src/components/Card.tsx @@ -0,0 +1,86 @@ +import * as React from 'react'; + +import cn from '@/utils/classnames'; + +const Card = React.forwardRef< +HTMLDivElement, +React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)); +Card.displayName = 'Card'; + +const CardHeader = React.forwardRef< +HTMLDivElement, +React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)); +CardHeader.displayName = 'CardHeader'; + +const CardTitle = React.forwardRef< +HTMLParagraphElement, +React.HTMLAttributes +>(({ className, ...props }, ref) => ( +

+)); +CardTitle.displayName = 'CardTitle'; + +const CardDescription = React.forwardRef< +HTMLParagraphElement, +React.HTMLAttributes +>(({ className, ...props }, ref) => ( +

+)); +CardDescription.displayName = 'CardDescription'; + +const CardContent = React.forwardRef< +HTMLDivElement, +React.HTMLAttributes +>(({ className, ...props }, ref) => ( +

+)); +CardContent.displayName = 'CardContent'; + +const CardFooter = React.forwardRef< +HTMLDivElement, +React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)); +CardFooter.displayName = 'CardFooter'; + +export default Card; +export { + CardHeader, + CardFooter, + CardTitle, + CardDescription, + CardContent, +}; diff --git a/ts/browser-extension/src/components/Dialog.tsx b/ts/browser-extension/src/components/Dialog.tsx new file mode 100644 index 00000000..86b09688 --- /dev/null +++ b/ts/browser-extension/src/components/Dialog.tsx @@ -0,0 +1,120 @@ +import * as DialogPrimitive from '@radix-ui/react-dialog'; +import { X } from 'lucide-react'; +import * as React from 'react'; + +import cn from '@/utils/classnames'; + +const Dialog = DialogPrimitive.Root; + +const DialogTrigger = DialogPrimitive.Trigger; + +const DialogPortal = DialogPrimitive.Portal; + +const DialogClose = DialogPrimitive.Close; + +const DialogOverlay = React.forwardRef< +React.ElementRef, +React.ComponentPropsWithoutRef & { className?: string } +>(({ className, ...props }, ref) => ( + +)); +DialogOverlay.displayName = DialogPrimitive.Overlay.displayName; + +const DialogContent = React.forwardRef< +React.ElementRef, +React.ComponentPropsWithoutRef & { className?: string } +>(({ className, children, ...props }, ref) => ( + + + + {children} + + + Close + + + +)); +DialogContent.displayName = DialogPrimitive.Content.displayName; + +const DialogHeader = ({ + className, + ...props +}: React.HTMLAttributes) => ( +
+); +DialogHeader.displayName = 'DialogHeader'; + +const DialogFooter = ({ + className, + ...props +}: React.HTMLAttributes) => ( +
+); +DialogFooter.displayName = 'DialogFooter'; + +const DialogTitle = React.forwardRef< +React.ElementRef, +React.ComponentPropsWithoutRef & { className?: string } +>(({ className, ...props }, ref) => ( + +)); +DialogTitle.displayName = DialogPrimitive.Title.displayName; + +const DialogDescription = React.forwardRef< +React.ElementRef, +React.ComponentPropsWithoutRef & { className?: string } +>(({ className, ...props }, ref) => ( + +)); +DialogDescription.displayName = DialogPrimitive.Description.displayName; + +export default Dialog; +export { + DialogPortal, + DialogOverlay, + DialogClose, + DialogTrigger, + DialogContent, + DialogHeader, + DialogFooter, + DialogTitle, + DialogDescription, +}; diff --git a/ts/browser-extension/src/components/Form.tsx b/ts/browser-extension/src/components/Form.tsx new file mode 100644 index 00000000..34cf5aa3 --- /dev/null +++ b/ts/browser-extension/src/components/Form.tsx @@ -0,0 +1,179 @@ +/* eslint-disable react-refresh/only-export-components */ +import * as LabelPrimitive from '@radix-ui/react-label'; +import { Slot } from '@radix-ui/react-slot'; +import * as React from 'react'; +import { + Controller, + type ControllerProps, + type FieldPath, + type FieldValues, + FormProvider, + useFormContext, +} from 'react-hook-form'; + +import Label from './Label'; + +import cn from '@/utils/classnames'; + +const Form = FormProvider; + +type FormFieldContextValue< + TFieldValues extends FieldValues = FieldValues, + TName extends FieldPath = FieldPath +> = { + name: TName, +}; + +const FormFieldContext = React.createContext( + {} as FormFieldContextValue +); + +const FormField = < + TFieldValues extends FieldValues = FieldValues, + TName extends FieldPath = FieldPath +>({ + ...props +}: ControllerProps) => { + return ( + + + + ); +}; + +const useFormField = () => { + const fieldContext = React.useContext(FormFieldContext); + const itemContext = React.useContext(FormItemContext); + const { getFieldState, formState } = useFormContext(); + + const fieldState = getFieldState(fieldContext.name, formState); + + if (!fieldContext.name) { + throw new Error('useFormField should be used within '); + } + + const { id } = itemContext; + + return { + id, + name: fieldContext.name, + formItemId: `${id}-form-item`, + formDescriptionId: `${id}-form-item-description`, + formMessageId: `${id}-form-item-message`, + ...fieldState, + }; +}; + +type FormItemContextValue = { + id: string, +}; + +const FormItemContext = React.createContext( + {} as FormItemContextValue +); + +const FormItem = React.forwardRef< +HTMLDivElement, +React.HTMLAttributes +>(({ className, ...props }, ref) => { + const id = React.useId(); + + return ( + +
+ + ); +}); +FormItem.displayName = 'FormItem'; + +const FormLabel = React.forwardRef< +React.ElementRef, +React.ComponentPropsWithoutRef & { className?: string } +>(({ className, ...props }, ref) => { + const { error, formItemId } = useFormField(); + + return ( +